# Change Log (AI/Human Curated) ## Entry Template ``` date: YYYY-MM-DD author: scope: type: change rationale: impact: status: completed|rolled-back|partial Summary: Validation: Follow-ups: ``` --- ### 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.js` with: - `normalizeRouteStateQuery(query)` - `resolveSearchResultsHref(options)` - Updated `components/breadcrumbs.js` to consume the shared helper for: - breadcrumb href resolution (`/myportal/viewall`, advanced/address/default results) - case-results breadcrumb target on `/case/[ticketnumber]` - preserving existing label selection behavior via normalized flags. - Updated `components/case/summary.js` to replace local `buildSearchHref` with shared helper output (`searchHref`), including DNS-route override and no-flag fallback behavior. - Added table-driven unit coverage in `tests/phase22/route-state-helper.test.cjs` and registered it in `tests/phase22/index.test.cjs`. Validation: - `npx eslint lib/routing/routeState.js components/breadcrumbs.js components/case/summary.js tests/phase22/route-state-helper.test.cjs tests/phase22/index.test.cjs` -> pass with 1 pre-existing warning in `components/case/summary.js` (`react-hooks/exhaustive-deps`). - `node tests/phase22/route-state-helper.test.cjs` -> pass (5/5). - `node tests/phase22/index.test.cjs` -> fails in existing auth suite (`tests/phase22/auth-redirect-safety.test.cjs`) with `ReferenceError: resolveLocale is not defined` in `pages/api/auth/[...nextauth].js`; unrelated to route-state changes. Follow-ups: - If needed, triage/fix the existing phase22 auth redirect test harness failure separately to restore full combined suite execution. - Expand helper adoption in future slices to other navigation decision call sites if additional duplication emerges. ### CL-22541-B: breadcrumb route-state helper expansion (label + DNS path helper) date: 2026-04-09 author: Cline scope: `lib/routing/routeState.js`, `components/breadcrumbs.js`, `components/case/summary.js`, `tests/phase22/route-state-helper.test.cjs` type: change rationale: Continue Priority 3 breadcrumb refactor in a second bounded commit by extracting remaining repeated breadcrumb label and DNS-route-path decision logic into shared pure helpers. impact: Refactor-only extraction for navigation decision logic; no auth/session/CSP/API changes; no intended EN/CY behavior change beyond internal logic centralization. status: completed Summary: - Extended `lib/routing/routeState.js` with: - `resolveSearchBreadcrumbLabel(...)` - `isDnsRoutePath(pathname)` - Updated `components/breadcrumbs.js` to use `resolveSearchBreadcrumbLabel(...)` and removed inline label decision IIFE. - Updated `components/case/summary.js` to use `isDnsRoutePath(router.pathname)` and removed inline DNS path checks. - Expanded `tests/phase22/route-state-helper.test.cjs` with coverage for: - breadcrumb label resolution matrix - DNS path detection helper Validation: - `npx eslint lib/routing/routeState.js components/breadcrumbs.js components/case/summary.js tests/phase22/route-state-helper.test.cjs` -> pass with 1 pre-existing warning in `components/case/summary.js` (`react-hooks/exhaustive-deps`). - `node tests/phase22/route-state-helper.test.cjs` -> pass (7/7). - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next breadcrumbs slice can target incremental decomposition of large pathname branch rendering blocks in `components/breadcrumbs.js` into grouped render helpers with behavior parity. ### CL-22541-C: breadcrumb case-state bundling helper (single-call resolver) date: 2026-04-09 author: Cline scope: `lib/routing/routeState.js`, `components/breadcrumbs.js`, `tests/phase22/route-state-helper.test.cjs` type: change rationale: Continue Priority 3 breadcrumbs refactor by bundling repeatedly paired breadcrumb href/label resolution into one pure helper so component call sites stay thinner and less drift-prone. impact: Refactor-only centralization of existing route-state composition logic; no intended auth/session/API/i18n behavior change. status: completed Summary: - Added `resolveCaseBreadcrumbState(...)` in `lib/routing/routeState.js` to return: - `breadcrumbHref` - `caseResultsHref` - `breadcrumbLabel` - Updated `components/breadcrumbs.js` to replace three separate helper invocations with one resolver call. - Extended `tests/phase22/route-state-helper.test.cjs` with bundled case-state resolver coverage. Validation: - `npx eslint lib/routing/routeState.js components/breadcrumbs.js tests/phase22/route-state-helper.test.cjs` -> pass. - `node tests/phase22/route-state-helper.test.cjs` -> pass (8/8). - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next bounded slice can extract grouped pathname render blocks from `components/breadcrumbs.js` (data-driven map or small render helpers) while preserving route parity. ### CL-22541-D: breadcrumbs shared my-portal crumb helper extraction date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js` type: change rationale: Continue bounded breadcrumbs decomposition by extracting repeated my-portal breadcrumb `
  • ` markup into one local render helper to reduce duplication and keep follow-on slices safer. impact: Refactor-only JSX deduplication in breadcrumb rendering; no intended route, auth/session, API, EN/CY, or accessibility behavior change. status: completed Summary: - Added local `renderMyPortalCrumb()` helper in `components/breadcrumbs.js`. - Replaced repeated identical my-portal crumb JSX in multiple `/myportal/*` route branches with helper calls. - Kept special-case crumbs untouched where label/href differs (e.g. `newappeal` parent-title crumb, `cyMyPortalHref` account branches). Validation: - `npx eslint components/breadcrumbs.js` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next bounded slice can target additional repeated breadcrumb list-item patterns (e.g., repeated case-reference tail item blocks) with same behavior parity approach. ### CL-22541-E: breadcrumbs case-reference crumb helper extraction date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js` type: change rationale: Continue bounded breadcrumbs decomposition by extracting repeated case-reference tail breadcrumb markup into one local helper and replacing repeated inline blocks. impact: Refactor-only JSX deduplication in breadcrumb rendering; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added local `renderCaseReferenceCrumb(referenceValue)` helper in `components/breadcrumbs.js`. - Replaced repeated `{t("common:breadcrumb-case-reference")}: ...` list-item blocks across case/dns route branches with helper calls. - Corrected initial over-wrap by using helper calls directly (so generated `
  • ` is not nested in another `
  • `). 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 preserve `router.back()` behavior. - Combined with existing `renderMyPortalCrumb` and `renderCaseReferenceCrumb` helpers for more consistent branch composition. Validation: - `npx eslint components/breadcrumbs.js` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next slice recommendation: extract remaining repeated inline link crumbs for case/DNS branches that still hardcode `
  • ` (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 `
  • ` 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 (`` and occasional ``) 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)` in `components/breadcrumbs.js` for repeated `` breadcrumb actions. - Replaced repeated anchor/back-link crumb blocks in: - `/myportal/searchresults` my-portal anchor crumb - `/newappeal/[appealtypes]` and `/myportal/[appealtypes]` step-back crumbs - `/myportal/representation` back-chevron action crumbs (all three state branches) - Preserved original click handlers, href values, and class semantics (`govuk-breadcrumbs__link-item`, `backChevron`) to keep behavior parity. Validation: - `npx eslint components/breadcrumbs.js` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next slice recommendation: consolidate remaining one-off inline breadcrumb `
  • ` blocks still present in edge branches (e.g., `/newappeal/[appealtypes]`, `/myportal/[appealtypes]`, `/case`) and consider introducing an optional `renderBackCrumb(...)` semantic wrapper for readability. ### CL-22541-I: breadcrumbs edge branch consolidation + semantic back-crumb wrapper date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js` type: change rationale: Continue the same bounded breadcrumbs refactor cadence by consolidating remaining edge inline Link/back crumbs and introducing a semantic back-crumb wrapper for readability. impact: Refactor-only JSX deduplication/readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added semantic helper `renderBackCrumb(onClick, listItemClass?)` that delegates to `renderAnchorCrumb(...)` with existing back-link text. - Replaced remaining one-off inline edge crumbs in: - `/newappeal/[appealtypes]` and `/myportal/[appealtypes]` (`currentSection === 9999` service-name link and back-link branch) - `/case` search-results link crumb (including existing `router.back()` callback) - `/myportal/representation` back-link branches now use `renderBackCrumb(...)`. - Preserved existing href targets, callback behavior, and class semantics (including special `govuk-breadcrumbs__link-item` usage). Validation: - `npx eslint components/breadcrumbs.js` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next slice recommendation: consider extracting a small, route-keyed breadcrumb branch map/helper grouping in `components/breadcrumbs.js` (purely structural) to reduce the long inline conditional chain while keeping one-slice behavior parity. ### CL-22541-J: breadcrumbs static text-only route crumb consolidation date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js` type: change rationale: Continue the same bounded refactor cadence by consolidating repeated static text-only breadcrumb route branches into one route-label resolver. impact: Refactor-only structural deduplication/readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `getStaticTextCrumbLabel(path)` in `components/breadcrumbs.js` to centralize static text-only crumb labels by pathname. - Replaced repeated single-line static crumb branches with one generic render path: - `renderTextCrumb(getStaticTextCrumbLabel(pathname))` when mapping returns a label. - Consolidated static branch handling for routes including: - account register - DNS index/help/contact/applications process pages - cookies/privacy/accessibility/static auth routes. - Preserved route labels (including translation keys and legacy hardcoded labels where already present). Validation: - `npx eslint components/breadcrumbs.js` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next slice recommendation: extract a small grouped helper for recurring two-crumb route pairs (e.g., my-portal + section label, dns list + case reference) to reduce the remaining conditional chain while preserving explicit route behavior. ### CL-22541-K: breadcrumbs grouped two-crumb helper extraction date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js` type: change rationale: Continue the same bounded refactor cadence by extracting recurring two-crumb patterns into small grouped helpers while preserving explicit route branches. impact: Refactor-only readability/deduplication improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added grouped helper `renderMyPortalSectionCrumbs(sectionLabel)` for recurring my-portal + section text pairs. - Added grouped helper `renderDnsCaseReferenceCrumbs(referenceValue)` for recurring DNS applications link + case-reference pairs. - Replaced duplicated route branches with grouped helper usage for: - `/myportal/addresssearch`, `/myportal/advancedsearch`, `/myportal/contactus` - `/dnsdetails`, `/dns/[developmentName]` - Preserved existing href behavior (including EN/CY DNS applications link), labels, and case-reference rendering. Validation: - `npx eslint components/breadcrumbs.js` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next slice recommendation: extract a small route-to-renderer map for static single-branch crumbs (where branch has no bespoke side-effects) so the main JSX conditional chain shrinks further without altering explicit behavior in dynamic/sensitive branches. ### CL-22541-L: breadcrumbs simple-route renderer map introduction date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js` type: change rationale: Continue bounded readability refactor by introducing a small route-to-renderer map for simple static branches, reducing conditional-chain length while preserving explicit dynamic branches. impact: Refactor-only structural deduplication/readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `getSimpleRouteRenderer(path)` in `components/breadcrumbs.js` for simple routes with no bespoke side effects. - Introduced a single invocation block that resolves and renders mapped simple routes when present. - Migrated simple route branches into the map, including: - `/myportal`, `/searchresults`, `/advancedsearch`, `/addresssearch`, `/contactus` - `/viewall`, `/myportal/dnsapplications` - Preserved existing label text, helper usage, and rendered crumb sequence semantics. Validation: - `npx eslint components/breadcrumbs.js` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next slice recommendation: extract a second tiny map for simple "link + text" pair routes (no callbacks, no side effects) to further shrink the conditional chain while keeping callback/dynamic branches explicit. ### CL-22541-M: breadcrumbs simple link+text pair map + focused structure coverage date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js`, `tests/phase22/{breadcrumbs-route-map-structure,index}.test.cjs` type: change rationale: Execute the next bounded slice by extracting simple link+text pair route branches into a tiny renderer map and adding focused regression checks that mapped and dynamic callback branches remain in the intended structure. impact: Refactor-only structural deduplication/readability improvement plus focused test coverage; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `getSimpleLinkTextPairRenderer(path)` in `components/breadcrumbs.js` for simple no-callback "link + text" pair routes. - Migrated these routes into the new pair map: - `/addresssearchresults` - `/advancedsearchresults` - Kept dynamic/callback-driven branches explicit and untouched (e.g., `/myportal/case/id/[incident]` with `router.back()`). - Added focused phase22 suite `tests/phase22/breadcrumbs-route-map-structure.test.cjs` asserting: - mapped simple pair routes exist in the new map - explicit dynamic callback branch remains present. - Registered the new suite in `tests/phase22/index.test.cjs`. Validation: - `npx eslint components/breadcrumbs.js tests/phase22/index.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite, including new breadcrumbs-route-map tests 2/2). Follow-ups: - Next slice recommendation: introduce a tiny local `renderMappedRoute(path, resolver)` helper to remove repeated inline IIFE map invocations, then optionally merge simple maps under one top-level resolver while preserving explicit ordering and side-effect-free constraints. ### CL-22541-N: breadcrumbs unified mapped-route resolver + widened structural guardrails date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js`, `tests/phase22/breadcrumbs-route-map-structure.test.cjs` type: change rationale: Execute the requested wider next slice by removing duplicated mapped-route invocation patterns, introducing a single top-level mapped resolver with explicit precedence, and migrating an additional safe my-portal route group into map-driven rendering while preserving explicit dynamic/callback branches. impact: Refactor-only structural consolidation/readability improvement with widened mapped-route coverage and stronger structure guardrail tests; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `getSimpleMyPortalRouteRenderer(path)` in `components/breadcrumbs.js` and migrated additional safe map-friendly routes: - `/myportal/searchresults` - `/myportal/addresssearch` - `/myportal/advancedsearch` - `/myportal/contactus` - `/myportal/viewall` - Added `resolveMappedRouteRenderer(path)` to unify map precedence under one resolver. - Added `renderMappedRoute(path, resolver?)` helper and replaced duplicated inline map IIFE invocations with a single call: - `{renderMappedRoute(pathname)}` - Kept dynamic/stateful callback branches explicit and unchanged, especially `/myportal/case/id/[incident]` (`router.back()`) and other callback/state driven branches. - Expanded `tests/phase22/breadcrumbs-route-map-structure.test.cjs` to assert: - new my-portal route-map entries are present - unified resolver/helper signatures are present - single mapped-route invocation is used in JSX - dynamic callback branch remains explicit. Validation: - `npx eslint components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite; breadcrumbs-route-map tests 3/3). Follow-ups: - Next wider slice candidate: move a second safe myportal results pair group (`/myportal/advancedsearchresults`, `/myportal/addresssearchresults`) into the unified mapped resolver where callback-free, then consider splitting resolver maps into a dedicated local constant section for improved scanability. ### CL-22541-O: breadcrumbs myportal results-pair migration into unified mapped resolver date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js`, `tests/phase22/breadcrumbs-route-map-structure.test.cjs` type: change rationale: Execute the agreed next slice by migrating the remaining callback-free myportal results-pair branches into the unified mapped resolver so more safe branches are rendered through one consistent mapping flow. impact: Refactor-only structural consolidation/readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Extended `getSimpleMyPortalRouteRenderer(path)` to include: - `/myportal/advancedsearchresults` - `/myportal/addresssearchresults` - Removed now-redundant explicit conditional branches for those two routes from the main JSX chain. - Kept callback/stateful branches explicit and unchanged (notably `/myportal/case/id/[incident]` with `router.back()`). - Expanded `tests/phase22/breadcrumbs-route-map-structure.test.cjs` guardrails to assert: - both myportal results-pair routes are mapped - legacy explicit `isPath(...)` branches for those routes are no longer present Validation: - `npx eslint components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite; breadcrumbs-route-map tests 3/3). Follow-ups: - Next wider slice candidate: split map resolver sections into clearly named grouped constants (simple/public/myportal) near one composition point, then optionally move map-only route renderers to a local pure helper module if continued growth impacts scanability. ### CL-22541-P: breadcrumbs grouped route-map constants + unified map composition point date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js`, `tests/phase22/breadcrumbs-route-map-structure.test.cjs` type: change rationale: Execute the next wider slice by replacing per-group resolver functions with grouped route-map constants and a single composition array to further improve scanability while preserving route precedence semantics. impact: Refactor-only structural readability improvement; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Replaced function-based map accessors with grouped route-map constants in `components/breadcrumbs.js`: - `simpleRouteRenderersByPath` - `simpleLinkTextPairRenderersByPath` - `simpleMyPortalRouteRenderersByPath` - Added unified map composition point: - `mappedRouteRendererMaps` (ordered array preserving precedence) - `getMappedRendererByPath(path, routeRendererMap)` helper - Updated `resolveMappedRouteRenderer(path)` to iterate the composed map list while retaining previous resolution order and behavior. - Kept dynamic/callback branches explicit and unchanged outside map-driven paths. - Expanded structure tests to assert grouped map composition contracts (`mappedRouteRendererMaps`, `getMappedRendererByPath`) in addition to existing resolver and invocation guardrails. Validation: - `npx eslint components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite; breadcrumbs-route-map tests 3/3). Follow-ups: - Next slice option A (larger): extract map constants + resolver helpers into a local `lib/routing/breadcrumbRouteMaps.js` pure module with focused tests, keeping callback/stateful branch rendering in component. - Next slice option B (smaller): expand structure tests to assert explicit map ordering invariants so future reordering regressions are caught early. ### CL-22541-Q: breadcrumbs route-map helper module extraction + map-order invariants date: 2026-04-09 author: Cline scope: `lib/routing/breadcrumbRouteMaps.js`, `components/breadcrumbs.js`, `tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure,index}.test.cjs` type: change rationale: Execute both queued follow-up slices together by extracting map composition/resolution logic into a pure routing helper module and adding stronger structure + pure-helper guardrails for map-order precedence. impact: Refactor-only structural modularization and test hardening; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added new pure helper module `lib/routing/breadcrumbRouteMaps.js`: - `buildBreadcrumbRendererMaps(...)` - `getMappedRendererByPath(...)` - `resolveMappedRouteRenderer(...)` - Updated `components/breadcrumbs.js` to import/use shared helper logic: - map composition now via `buildBreadcrumbRendererMaps(...)` - resolver now delegates to `resolveMappedRouteRendererByMaps(...)` - dynamic/callback-sensitive explicit branches remain unchanged. - Added focused pure-helper tests in `tests/phase22/breadcrumb-route-maps-helper.test.cjs` for: - map build order - map lookup null/renderer behavior - resolver precedence behavior - Expanded `tests/phase22/breadcrumbs-route-map-structure.test.cjs` to assert: - component imports shared breadcrumb route-map helper module - resolver delegation uses helper module - map builder call preserves explicit ordering (simple -> link-text -> myportal) - Updated `tests/phase22/index.test.cjs` to include the new helper suite. Validation: - `npx eslint lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite; breadcrumb-route-maps-helper 3/3; breadcrumbs-route-map 3/3). Follow-ups: - Next slice option A (larger): move per-path map object declarations out of `components/breadcrumbs.js` into module-level pure factories (still injected with `t/router/currentView`) to further shrink component body. - Next slice option B (smaller): add one focused parity test asserting mapped resolver fallback returns `null` in component rendering path for non-mapped routes (ensures no accidental render noise). ### CL-22541-R: breadcrumbs mapped-group factory composition + unmapped-route null parity guard date: 2026-04-09 author: Cline scope: `lib/routing/breadcrumbRendererFactories.js`, `components/breadcrumbs.js`, `tests/phase22/breadcrumbs-route-map-structure.test.cjs` type: change rationale: Execute both approved next slices in one commit by centralizing deterministic mapped route-group composition into a factory-level helper and adding explicit structure guard coverage for null fallback behavior on unmapped routes. impact: Refactor-only structural consolidation and test hardening; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `createMappedRouteRendererGroups(...)` in `lib/routing/breadcrumbRendererFactories.js` to compose and return all deterministic mapped renderer groups in one place: - `simpleRouteRenderersByPath` - `simpleLinkTextPairRenderersByPath` - `simpleMyPortalRouteRenderersByPath` - `caseDetailRouteRenderersByPath` - `detailAndAccountRouteRenderersByPath` - Updated `components/breadcrumbs.js` to consume `createMappedRouteRendererGroups(...)` and remove local per-group factory composition boilerplate while preserving existing map precedence and resolver flow. - Expanded `tests/phase22/breadcrumbs-route-map-structure.test.cjs` to assert: - grouped renderer maps are composed via `createMappedRouteRendererGroups(...)` - mapped rendering path explicitly preserves null fallback (`routeRenderer ? routeRenderer() : null`) Validation: - `npx eslint lib/routing/breadcrumbRendererFactories.js components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite; breadcrumbs-route-map 4/4). Follow-ups: - Next slice option A (larger): extract remaining deterministic inline branches (`/myportal/case`, `/case/id/[incident]` if kept deterministic after constraints review) only if they remain callback/state free. - Next slice option B (smaller): add one focused assertion in helper-level tests that empty grouped map entries are tolerated without affecting precedence resolution. ### CL-22541-S: breadcrumbs deterministic case-branch extraction (`/myportal/case`, `/case/id/[incident]`) date: 2026-04-09 author: Cline scope: `lib/routing/breadcrumbRendererFactories.js`, `components/breadcrumbs.js`, `tests/phase22/breadcrumbs-route-map-structure.test.cjs` type: change rationale: Execute the next deterministic extraction slice by migrating remaining callback-free case breadcrumb branches into the case-detail factory group while preserving map precedence and leaving stateful/callback routes inline. impact: Refactor-only structural extraction and test guardrail expansion; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Extended `createCaseDetailRouteRenderers(...)` in `lib/routing/breadcrumbRendererFactories.js` to map: - `/myportal/case` - `/case/id/[incident]` - Injected additional deterministic inputs required by these routes: - `currentReference` - `nestedSearchString` - Updated `createMappedRouteRendererGroups(...)` wiring to pass the new inputs to case-detail factory composition. - Updated `components/breadcrumbs.js` to pass `nestedSearchString` into grouped factory composition. - Removed now-redundant inline `isPath(...)` branches for: - `/myportal/case` - `/case/id/[incident]` - Expanded `tests/phase22/breadcrumbs-route-map-structure.test.cjs` to assert: - both new routes are mapped in `createCaseDetailRouteRenderers` - both inline branches are absent from `components/breadcrumbs.js` Validation: - `npx eslint lib/routing/breadcrumbRendererFactories.js components/breadcrumbs.js tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite; breadcrumbs-route-map 4/4). Follow-ups: - Next slice option A (larger): evaluate whether any remaining deterministic inline branches can be extracted without violating callback/state constraints. - Next slice option B (smaller): add a focused helper-level precedence test where earlier map contains falsy/non-function values and later maps contain valid renderers. ### CL-22541-T: breadcrumbs larger slice — new-appeal mapped group extraction (`/newappeal/selectappeal`) date: 2026-04-09 author: Cline scope: `lib/routing/{breadcrumbRendererFactories,breadcrumbRouteMaps}.js`, `components/breadcrumbs.js`, `tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure}.test.cjs` type: change rationale: Execute the next larger deterministic refactor slice by extracting callback-free new-appeal breadcrumb branching into a dedicated mapped renderer group and extending map-order guardrails. impact: Refactor-only structural extraction plus precedence-test hardening; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `createNewAppealRouteRenderers(...)` in `lib/routing/breadcrumbRendererFactories.js`. - Mapped `/newappeal/selectappeal` into the new grouped renderer factory. - Extended grouped composition return from `createMappedRouteRendererGroups(...)` with `newAppealRouteRenderersByPath`. - Updated `lib/routing/breadcrumbRouteMaps.js` to include `newAppealRouteRenderersByPath` in explicit map precedence ordering. - Updated `components/breadcrumbs.js` to consume/pass `newAppealRouteRenderersByPath` into map builder. - Removed now-redundant inline `isPath("/newappeal/selectappeal")` branch from component JSX. - Expanded tests: - `tests/phase22/breadcrumbs-route-map-structure.test.cjs` - assert new factory export and mapped route presence - assert inline branch removal - assert updated map-order invariant (simple -> link-text -> myportal -> new-appeal -> case detail -> detail/account) - `tests/phase22/breadcrumb-route-maps-helper.test.cjs` - assert six-map ordering contract and updated grouped precedence wiring. Validation: - `npx eslint lib/routing/breadcrumbRendererFactories.js lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next larger slice candidate: evaluate extraction viability for `/case` branch only if callback/`router.back()` behavior can remain explicit and parity-safe. - Next smaller slice candidate: add helper-level test coverage for unexpected non-function map values and explicit skip behavior (defensive precedence guard). ### CL-22541-U: breadcrumbs smaller slice — defensive mapped-route resolver hardening date: 2026-04-09 author: Cline scope: `lib/routing/breadcrumbRouteMaps.js`, `tests/phase22/breadcrumb-route-maps-helper.test.cjs` type: change rationale: Execute the queued smaller slice by hardening mapped-route lookup against malformed map entries and non-function values while keeping precedence behavior unchanged. impact: Refactor-hardening only; no intended breadcrumb route behavior change for valid mapped renderers. status: completed Summary: - Updated `getMappedRendererByPath(...)` to safely handle invalid route-map entries: - returns `null` when map is missing/non-object - returns `null` when mapped value is not a function - Preserved existing resolver precedence semantics for valid function renderers. - Added focused helper test asserting resolver skips: - invalid map entries (`null`/`undefined`) - non-function mapped values and still resolves the first later valid renderer. Validation: - `npx eslint lib/routing/breadcrumbRouteMaps.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite; breadcrumb-route-maps-helper 5/5). Follow-ups: - Next larger slice: extract remaining callback-bearing deterministic branches into mapped route groups with callback injection, then update structure guards accordingly. ### CL-22541-V: breadcrumbs larger slice — callback route-group extraction (`/myportal/case/id/[incident]`, `/case`) date: 2026-04-09 author: Cline scope: `lib/routing/{breadcrumbRendererFactories,breadcrumbRouteMaps}.js`, `components/breadcrumbs.js`, `tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure}.test.cjs` type: change rationale: Execute the next larger extraction slice by moving callback-bearing breadcrumb branches into a dedicated callback renderer map while preserving `router.back()` behavior through explicit callback injection. impact: Structural refactor with preserved callback semantics; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `createCallbackRouteRenderers(...)` in `lib/routing/breadcrumbRendererFactories.js` to map: - `/myportal/case/id/[incident]` - `/case` - Introduced explicit callback injection (`onBack`) into grouped factory composition and route renderers, preserving `router.back()` behavior via injected callback. - Extended `createMappedRouteRendererGroups(...)` return with `callbackRouteRenderersByPath`. - Updated map builder in `lib/routing/breadcrumbRouteMaps.js` to include callback map in explicit precedence order: - simple -> link-text -> myportal -> new-appeal -> callback -> case detail -> detail/account. - Updated `components/breadcrumbs.js`: - pass `onBack: () => { router.back(); }` into grouped factory composition - include callback route map in `buildBreadcrumbRendererMaps(...)` - remove now-redundant inline `isPath("/myportal/case/id/[incident]")` and `isPath("/case")` branches. - Expanded tests: - `tests/phase22/breadcrumb-route-maps-helper.test.cjs` - update grouped map order assertions to seven maps including callback group. - `tests/phase22/breadcrumbs-route-map-structure.test.cjs` - assert callback factory export and mapped callback route presence - assert callback map inclusion in component grouped destructuring and map-order invariant - assert inline callback branches are removed while `router.back();` remains preserved. Validation: - `npx eslint lib/routing/breadcrumbRendererFactories.js lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next smaller slice candidate: add a focused helper test for empty-string/whitespace path lookups to assert strict null behavior for non-exact keys. - Next larger slice candidate: evaluate whether `/newappeal/[appealtypes]` and `/myportal/[appealtypes]` back-link branches can be extracted with explicit callback/setter injection while preserving state-step semantics. ### CL-22541-W: breadcrumbs larger slice — step-back route-group extraction (`/newappeal/[appealtypes]`, `/myportal/[appealtypes]`) date: 2026-04-09 author: Cline scope: `lib/routing/{breadcrumbRendererFactories,breadcrumbRouteMaps}.js`, `components/breadcrumbs.js`, `tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure}.test.cjs` type: change rationale: Execute the next larger extraction slice by moving step-based back-link branches into a dedicated mapped route group with explicit setter callback injection, preserving section-navigation semantics. impact: Structural refactor with preserved back-link and step-state behavior; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `createStepBackRouteRenderers(...)` in `lib/routing/breadcrumbRendererFactories.js` to map: - `/newappeal/[appealtypes]` - `/myportal/[appealtypes]` - Preserved existing step semantics in mapped handlers: - no crumb when `currentSection <= 1` - service-name crumb when `currentSection === 9999` - back-link crumb with existing class parity (`govuk-breadcrumbs__link-item` for new-appeal flow) - Introduced explicit injected handlers (`onStepBack`, `onStepBackWithInlineClass`) and injected crumb renderer dependency (`renderBackCrumb`) into grouped factory composition. - Extended map builder in `lib/routing/breadcrumbRouteMaps.js` with `stepBackRouteRenderersByPath` and updated precedence order: - simple -> link-text -> myportal -> new-appeal -> callback -> step-back -> case detail -> detail/account. - Updated `components/breadcrumbs.js`: - pass `currentSection` and step-back callbacks into `createMappedRouteRendererGroups(...)` - include step-back map in `buildBreadcrumbRendererMaps(...)` - remove inline `isPath("/newappeal/[appealtypes]")` and `isPath("/myportal/[appealtypes]")` branches. - Expanded tests: - `tests/phase22/breadcrumb-route-maps-helper.test.cjs` - updated grouped map count/order to include step-back map (8 total) - `tests/phase22/breadcrumbs-route-map-structure.test.cjs` - assert step-back factory export + mapped route presence - assert grouped destructuring includes step-back map - assert inline step-back branches are removed - assert updated map-order invariant includes step-back group. Validation: - `npx eslint lib/routing/breadcrumbRendererFactories.js lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next smaller slice candidate: add focused helper test for strict null behavior on empty-string/whitespace/non-exact path keys. - Next larger slice candidate: evaluate extractability of `/myportal/representation` back-link states via explicit callback injection, only if questionnaire/submit side-effects remain parity-safe and readable. ### CL-22541-X: breadcrumbs smaller slice — strict null lookup guard coverage (empty/whitespace/non-exact paths) date: 2026-04-09 author: Cline scope: `tests/phase22/breadcrumb-route-maps-helper.test.cjs` type: change rationale: Execute the queued smaller follow-up slice by hardening helper regression coverage for strict exact-match route lookup semantics. impact: Test-only hardening; no runtime route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added focused helper-level test case in `tests/phase22/breadcrumb-route-maps-helper.test.cjs`: - `resolveMappedRouteRenderer returns null for empty, whitespace, and non-exact path variants` - New assertions verify resolver returns `null` for: - empty path (`""`) - whitespace-only path (`" "`) - trailing/leading whitespace variants (`"/known "`, `" /known"`) - case-variant non-exact key (`"/KNOWN"`) - Confirms route-map resolver remains strict/exact and does not auto-trim or case-normalize lookup keys. Validation: - `npx eslint tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite; breadcrumb-route-maps-helper 6/6). Follow-ups: - Next larger slice candidate remains `/myportal/representation` callback/state branch extraction only if side-effects can be injected/parity-preserved cleanly. ### CL-22541-Y: breadcrumbs larger slice — representation route-group extraction (`/myportal/representation`) date: 2026-04-09 author: Cline scope: `lib/routing/{breadcrumbRendererFactories,breadcrumbRouteMaps}.js`, `components/breadcrumbs.js`, `tests/phase22/{breadcrumb-route-maps-helper,breadcrumbs-route-map-structure}.test.cjs` type: change rationale: Execute the queued larger follow-up slice by extracting `/myportal/representation` callback/state breadcrumb branches into a dedicated mapped route group with explicit callback injection while preserving questionnaire/submit side-effects. impact: Structural refactor with preserved representation back-link state behavior; no intended route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `createRepresentationRouteRenderers(...)` in `lib/routing/breadcrumbRendererFactories.js` mapping: - `/myportal/representation` - Preserved existing representation-state semantics in mapped handler: - submit/back from confirmation (`setRepresentationSubmit(qcount)`) - non-questionnaire back path (`setRepresentationSubmit(false)`) - questionnaire step-back path (`setShowQuestionnaireSection(showQuestionnaireSection - 1)` + `setRepresentationSubmit(false)`) - Introduced explicit injected state/callback dependencies into grouped composition: - `currentView`, `hasRepDetails`, `repDetails`, `showQuestionnaireSection` - `onRepresentationSubmitBackFromConfirmation` - `onRepresentationSubmitBackToDetails` - `onRepresentationQuestionnaireBack` - Extended `buildBreadcrumbRendererMaps(...)` in `lib/routing/breadcrumbRouteMaps.js` with `representationRouteRenderersByPath` and updated precedence order: - simple -> link-text -> myportal -> new-appeal -> callback -> step-back -> representation -> case detail -> detail/account. - Updated `components/breadcrumbs.js`: - pass representation state/callback injections into `createMappedRouteRendererGroups(...)` - include `representationRouteRenderersByPath` in map builder call - remove inline `isPath("/myportal/representation")` branch block. - Expanded tests: - `tests/phase22/breadcrumb-route-maps-helper.test.cjs` - updated map-count/order assertions to include representation group (9 total) - updated map build fixtures to include `representationRouteRenderersByPath` - `tests/phase22/breadcrumbs-route-map-structure.test.cjs` - assert representation factory export + mapped route presence - assert grouped destructuring includes representation map - assert inline representation branch removal - assert updated map-order invariant includes representation group. Validation: - `npx eslint lib/routing/breadcrumbRendererFactories.js lib/routing/breadcrumbRouteMaps.js components/breadcrumbs.js tests/phase22/breadcrumb-route-maps-helper.test.cjs tests/phase22/breadcrumbs-route-map-structure.test.cjs tests/phase22/index.test.cjs` -> pass. - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Next smaller slice candidate: helper-level assertion for missing/undefined representation dependency values yielding no renderer output regressions. - Next larger slice candidate: evaluate whether remaining `/newappeal` edge branch can be absorbed into mapped grouping without reducing readability or explicitness. ### CL-22541-Z: breadcrumbs closure slice 1 — mapped-route precedence/callback invariants decision date: 2026-04-09 author: Cline scope: `memory-bank/decisions.md` type: change rationale: Execute closure slice 1 by documenting explicit architectural invariants for breadcrumb mapped-route precedence and callback injection contracts so future refactors remain safe and auditable. impact: Documentation/governance hardening only; no runtime route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added `D-006` to `memory-bank/decisions.md`. - Captured accepted invariant contracts for: - explicit breadcrumb map precedence ordering (9 groups) - callback/state behavior dependency injection requirement (no ad-hoc inline reintroduction) - structure test guardrails as contract checks for intentional future changes. Validation: - Documentation consistency review against current breadcrumb map structure and phase22 structure test expectations. Follow-ups: - Closure slice 2: add focused negative-path representation map/dependency tolerance test coverage. - Closure slice 3: resolve and guard remaining `/newappeal` inline edge branch treatment. ### CL-22541-Z2: breadcrumbs closure slice 2 — missing representation map negative-path guard date: 2026-04-09 author: Cline scope: `tests/phase22/breadcrumb-route-maps-helper.test.cjs` type: change rationale: Execute closure slice 2 by adding focused negative-path coverage ensuring resolver behavior remains stable when representation route-map dependency is missing from grouped map input. impact: Test hardening only; no runtime route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Added focused helper-level test: - `resolveMappedRouteRenderer tolerates missing representation map entry in grouped map input` - New assertions verify: - missing `representationRouteRenderersByPath` resolves `/myportal/representation` to `null` - later maps still resolve correctly (case detail fallback remains intact). Validation: - `node tests/phase22/breadcrumb-route-maps-helper.test.cjs` -> pass (7/7). - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Closure slice 3: resolve and guard remaining `/newappeal` inline edge branch treatment. ### CL-22541-Z3: breadcrumbs closure slice 3 — remove lingering `/newappeal` no-op inline branch date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js`, `tests/phase22/breadcrumbs-route-map-structure.test.cjs` type: change rationale: Execute closure slice 3 by resolving the remaining inline `/newappeal` edge branch (a no-op render guard) and locking its removal with explicit structure coverage. impact: Refactor/test hardening only; no runtime route/auth/session/API/EN-CY/a11y behavior change. status: completed Summary: - Removed lingering no-op branch from breadcrumbs JSX: - deleted `{isPath("/newappeal") && <>}` - Added structure guard assertion that `/newappeal` inline branch is absent. Validation: - `node tests/phase22/breadcrumbs-route-map-structure.test.cjs` -> pass (4/4). - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Breadcrumb route-state extraction closure slices (1/2/3) complete. ### CL-22541-Z4: breadcrumbs post-closure hotfix — callable label resolver parity (static + view-all) date: 2026-04-09 author: Cline scope: `components/breadcrumbs.js`, `tests/phase22/breadcrumbs-route-map-structure.test.cjs` type: change rationale: Fix post-refactor regression where some breadcrumbs rendered blank labels because mapped label entries were returned as function references instead of resolved values. impact: Restores user-visible breadcrumb labels for static and view-all keyed routes; no auth/session/API/security behavior change. status: completed Summary: - Fixed static text breadcrumb label resolver to invoke mapped label functions: - `getStaticTextCrumbLabel(path)` now resolves callable entries (`resolver ? resolver() : null`). - Fixed view-all label resolver parity to support both function-backed and string-backed map entries: - `getViewAllLabel(viewKey)` now invokes function entries and returns string entries directly. - Added structure guard assertions to prevent regression of callable label resolution behavior. Validation: - `node tests/phase22/breadcrumbs-route-map-structure.test.cjs` -> pass (4/4). - `node tests/phase22/index.test.cjs` -> pass (combined suite). Follow-ups: - Breadcrumb label resolver parity now aligned across mapped/static/view-all label paths. ### CL-22541-Z5: architecture comparison overview refresh (senior architecture review) date: 2026-04-09 author: Cline scope: `context/architecture-overview-2026-04-09.md` type: change rationale: User requested a fresh senior architecture review and comparison baseline covering scalability, maintainability, coupling, boundary quality, operational/deployment risk, and prioritized technical debt actions. impact: Documentation-only architecture guidance update; no runtime/auth/session/security/API behavior change. status: completed Summary: - Added new architecture comparison baseline document: - `context/architecture-overview-2026-04-09.md` - Included requested structure: 1. current architecture summary 2. strengths 3. risks (scalability, maintainability, coupling, weak boundaries, operational/deployment) 4. prioritized recommendations 5. low-risk next improvements - Added explicit comparison notes vs existing `context/architecture.md` and identified strategic focus areas for the next modernization wave. Validation: - Documentation coherence review against current repo architecture docs (`context/architecture.md`, `context/integration-map.md`, `context/project-overview.md`). Follow-ups: - Optionally elevate this architecture overview into a periodic architecture scorecard cadence and add measurable KPIs in memory-bank. ### CL-00X: 22500 `components/elements/index.js` Phase 1 helper extraction date: 2026-04-07 author: Cline scope: `components/elements/index.js`, `components/elements/helpers/fileUploadHelpers.js`, `components/elements/helpers/translationHelpers.js`, `memory-bank/refactor-backlog.md` type: change rationale: Execute Phase 1 of the approved `components/elements/index.js` decomposition plan by extracting pure helper logic only, reducing monolith coupling while preserving UI/component behavior. impact: No route/API contract changes; refactor-only extraction of translation/file-upload helper functions with expected behavior parity for EN/CY field labels, file naming, thumbnail icon mapping, and filename validation. status: completed Summary: - Created work branch from `origin/SIPS-Development`: `22500-elements-index-phase1`. - Added helper modules: - `components/elements/helpers/fileUploadHelpers.js` - `getThumbnailIconByMimeType` - `getDocumentTypePrefix` - `validateUploadFilename` - `components/elements/helpers/translationHelpers.js` - `getFieldTranslation` - `getPickListTranslation` - Updated `components/elements/index.js` to consume these helpers and removed duplicated inline helper implementations. - Kept field renderer/component placement and external prop contracts unchanged (Phase 1 non-goals respected). - Updated `memory-bank/refactor-backlog.md` with a phased Priority 6 track and Phase 1 guardrail-aligned acceptance criteria. Validation: - `npx eslint components/elements/index.js components/elements/helpers/fileUploadHelpers.js components/elements/helpers/translationHelpers.js` -> pass Follow-ups: - Phase 2: extract low-risk leaf field renderer components from `components/elements/index.js` in bounded slices. - Perform manual EN/CY + a11y smoke matrix on new appeal/myportal form journeys before merge. ### CL-00Y: 22500 `components/elements/index.js` Phase 2 leaf renderer extraction (Rich multiline) date: 2026-04-07 author: Cline scope: `components/elements/index.js`, `components/elements/fields/renderRichMultiline.js` type: change rationale: Continue the approved phased decomposition by extracting one low-risk leaf renderer (`RenderRichMultiline`) from the elements monolith while keeping existing field wiring and behavior intact. impact: Refactor-only move of rich multiline renderer implementation; no route/API/auth/security changes and no intended EN/CY behavior change. status: completed Summary: - Added `components/elements/fields/renderRichMultiline.js` containing the extracted `RenderRichMultiline` renderer. - Updated `components/elements/index.js` to import the extracted renderer and removed the inline duplicate implementation. - Kept `RichMultiLinefield` usage and props unchanged (same Redux Field component wiring and validation flow). Validation: - `npx eslint components/elements/index.js components/elements/fields/renderRichMultiline.js` -> pass Follow-ups: - Continue Phase 2 in bounded slices by extracting additional low-risk leaf renderers (e.g., `RenderMultiline` / `RenderTextfield`) with no behavior change. ### CL-00Z: 22500 `components/elements/index.js` Phase 2 leaf renderer extraction (Text + Multiline) date: 2026-04-07 author: Cline scope: `components/elements/index.js`, `components/elements/fields/renderTextfield.js`, `components/elements/fields/renderMultiline.js` type: change rationale: Complete the requested next bounded phase by extracting the additional low-risk leaf renderers (`RenderTextfield`, `RenderMultiline`) from the elements monolith into dedicated field modules while preserving existing wiring and behavior. impact: Refactor-only move of two renderer components; no intended changes to auth/API/security and no intended EN/CY behavior change. status: completed Summary: - Added `components/elements/fields/renderTextfield.js` and `components/elements/fields/renderMultiline.js`. - Updated `components/elements/index.js` to import the extracted renderers. - Removed inline `RenderTextfield` and `RenderMultiline` implementations from `index.js`. Validation: - `npx eslint components/elements/index.js components/elements/fields/renderTextfield.js components/elements/fields/renderMultiline.js` -> pass Follow-ups: - Continue Phase 2 by selecting the next lowest-risk leaf renderer extraction in a separate commit. ### CL-001: TASK22211 endpoint search-document contract consistency slice date: 2026-03-23 author: Cline scope: `pages/api/endpoint/{getsearchdocumenthistory_api,getsearchdocumenthistorypaged_api,getsearchdocumentdetails_api,getsearchdocumentdetailspaged_api,getsearchdocumentTypes_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Continue the endpoint contract-consistency stream by normalizing a coherent search-document handler cluster that still used raw error passthrough and noisy legacy logging patterns. impact: Improved negative-path consistency and safer error contract handling in search-document endpoints while preserving success payload behavior. status: completed Summary: - Branch created from `SIPS-Development`: `TASK22211-endpoint-search-document-contract-consistency`. - Standardized five search-document handlers to `respondError`/`respondSuccess` usage. - Added explicit required-input guards: - `DOCUMENT_ID_REQUIRED` for history/historypaged - `INCIDENT_ID_REQUIRED` for details/detailspaged/types - `ORDER_BY_REQUIRED`, `FIELD_SORT_REQUIRED`, `SHOW_NUMBER_OF_RECORDS_REQUIRED` for details-paged query requirements - Removed noisy direct logging in paged/details code paths. - Preserved success contract patterns (pass-through or transformed payloads where already established). - Expanded phase21 endpoint tests with missing-input, catch-path, and success parity assertions for this cluster. Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 11/11 - email-handler: 12/12 - endpoint-handler: 53/53 - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings; no new lint errors) Follow-ups: - Continue the next endpoint cluster using the same pattern (bounded slice + phase21 test expansion). - Keep response success payloads contract-stable and avoid broad relay/auth refactors in this stream. ### CL-002: TASK22211 endpoint token handler contract consistency slice date: 2026-03-23 author: Cline scope: `pages/api/endpoint/getToken.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Close out remaining non-standard endpoint contract handling by normalizing the legacy token endpoint to shared API response helpers and explicit error coding. impact: Improved endpoint error consistency and test coverage for token acquisition failures while preserving successful token payload passthrough. status: completed Summary: - Refactored `getToken.js` to use `respondSuccess` and `respondError` from `pages/api/middleware/apiResponse`. - Removed legacy raw `res.status(...).json(...)`/bare status assignment pattern and dead logging artifacts. - Added explicit catch-path contract: `TOKEN_FETCH_FAILED` with 400 status. - Added endpoint phase21 tests for: - success token payload passthrough - catch-path error contract assertion Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 11/11 - email-handler: 12/12 - endpoint-handler: 147/147 - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings; no new lint errors) Follow-ups: - Remaining outlier API handler for this consistency stream is `pages/api/file/generateappealpdfcopy.js` (not yet on shared response helpers). ### CL-003: TASK22211 endpoint contract-hardening stream backfill (all known slices) date: 2026-03-23 author: Cline scope: `pages/api/endpoint/*_api.js`, `pages/api/endpoint/getToken.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Backfill memory-bank traceability so the complete known TASK22211 contract-consistency stream is documented in one place now that memory-bank is being versioned. impact: Improves governance/auditability of API contract hardening, makes rollout and rollback analysis easier, and records exactly which endpoint clusters were normalized. status: completed Summary: - Backfilled all known TASK22211 slices currently on branch (in commit order): - `b57f3de` search-document endpoint contracts + phase21 coverage - `9af541a` my-portal retrieval endpoint contracts - `b880364` basic search endpoint contracts - `a106dea` DNS basic search endpoint contracts - `b5a3a62` portal module + LPA case endpoint contracts - `4601d7c` case detail endpoint contracts - `2959c7d` delete/watched-case endpoint contracts - `b59f13a` metadata + linked-case endpoint contracts - `bcf03a6` form + publication endpoint contracts - `e0e91c8` DNS + representation endpoint contracts - `98e159d` case creation + media endpoint contracts - `88e4586` advanced-search-paged endpoint contract - `cb69bbe` case update + CRM task endpoint contracts - `722ef98` hash + metadata endpoint contracts - `134f99c` address-search endpoint contract - `8b6ed73` new-appeal appeal-types endpoint contract - `eec59e8` token endpoint contract handling - Across the stream, handlers were standardized toward `respondSuccess`/`respondError`, required-input guards, and explicit negative-path error codes while preserving success payload compatibility. - Phase21 endpoint contract suite was expanded incrementally alongside each slice. Validation: - Stream validation baseline (latest known run): - `node tests/phase21/api-contract-slice1.test.cjs` -> pass (endpoint-handler 147/147) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Continue with remaining non-standard API outlier(s), notably `pages/api/file/generateappealpdfcopy.js`. - Keep future slices logged in this file at commit-time now that memory-bank is versioned. --- ### CL-004: TASK22224 file + static endpoint contract hardening bundle (phase21) date: 2026-03-23 author: Cline scope: `pages/api/file/{downloadblob,generateappealpdfcopy}.js`, `pages/api/endpoint/{getsipsmedia_api,getappealtypesfornewappeal_api}.js`, `tests/phase21/{file-handler-contract,endpoint-handler-contract}.test.cjs` type: change rationale: Deliver the agreed larger bounded slice for remaining non-standard file/static handlers, improving negative-path consistency while preserving current success payload behavior. impact: Standardized error envelopes/codes for download and generated PDF copy flows, method guard parity for static endpoints, and expanded phase21 contract coverage for both file and endpoint handlers. status: completed Summary: - `downloadblob.js`: - added explicit catch-path response via `respondError` with `DOWNLOAD_BLOB_FAILED` - kept success behavior intact (attachment header + raw file body) - removed dead internal helper (`streamToBuffer`) and tightened local declarations - `generateappealpdfcopy.js`: - removed unused imports/noisy console warnings - standardized required-input and negative-path contracts: - `INCIDENT_ID_REQUIRED` (400) - `CASE_NOT_FOUND` (404) - `FORM_COLLECTION_NOT_FOUND` (400) - `APPEAL_PDF_COPY_GENERATION_FAILED` (400) - preserved success output contract (PDF content headers + buffer body) - `getsipsmedia_api.js` and `getappealtypesfornewappeal_api.js`: - added method guard for non-GET requests using `METHOD_NOT_ALLOWED` (405) - preserved existing GET success payloads - Expanded phase21 tests: - `file-handler-contract.test.cjs`: added coverage for download failure + full generated PDF copy contract/negative paths - `endpoint-handler-contract.test.cjs`: added method guard tests for both static endpoints Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 17/17 - email-handler: 12/12 - endpoint-handler: 149/149 - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - If desired, next slice can target remaining file-route parity candidates outside this bundle, but this closes the planned TASK22224 scope. --- ### CL-005: TASK22224 downloadblob hotfix closure (path normalization + hash compatibility) date: 2026-03-23 author: Cline scope: `pages/api/file/downloadblob.js` type: change rationale: Close post-merge runtime regressions reported on live links where download URLs alternated between filename-only/full-path blob names and mixed encoded/raw hash input variants. impact: Restored reliable blob downloads without relaxing hash security guarantees (still HMAC validated), and preserved existing caller compatibility across legacy/new URL encodings. status: completed Summary: - Hotfix 1 (`f09f3b7`): normalized blob path resolution - accepts both forms of `blobname` input: - filename only (legacy) - full prefixed path (already includes `casefolderID/...`) - prevents double-prefix lookup failures - sets attachment filename from final path segment only - Hotfix 2 (`bd3bf68`): hash compatibility validation - validates against a bounded set of canonical query-path variants (raw/encoded combinations for `casefolderID` and `blobname`) - fixes `INVALID_HASH` false negatives for legitimate caller-generated links - keeps strict HMAC requirement in place (no unauthenticated bypass) Validation: - `node tests/phase21/file-handler-contract.test.cjs` -> pass (17/17) - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 17/17 - email-handler: 12/12 - endpoint-handler: 149/149 - User confirmation: "downloadblob now works" Follow-ups: - Next recommended slice on this branch: complete file-route guard parity for `deleteblob.js`, `deleteblobcase.js`, and `deleteblobrep.js` by aligning hash validation canonicalization and explicit `respondError` contracts (`MISSING_REQUIRED_QUERY`, `INVALID_HASH`, operation-specific `*_FAILED`). - Extend `tests/phase21/file-handler-contract.test.cjs` for the above routes with mixed encoded/raw hash cases to lock compatibility. --- ### CL-006: TASK22224 file delete-route guard parity slice date: 2026-03-23 author: Cline scope: `pages/api/file/{deleteblob,deleteblobcase,deleteblobrep}.js`, `tests/phase21/file-handler-contract.test.cjs` type: change rationale: Execute the next planned slice to align hash/canonicalization behavior and negative-path contracts across high-risk file delete routes, matching the compatibility posture established for `downloadblob`. impact: Reduces false `INVALID_HASH` failures for legitimate encoded/raw caller variants while preserving strict hash enforcement and improving resilience via explicit catch-path contracts. status: completed Summary: - `deleteblob.js` - added bounded hash candidate validation for encoded/raw combinations of `casefolderID` and `blobname` - normalized delete path handling for both filename-only and already-prefixed blob paths - added explicit catch-path contract: `DELETE_BLOB_FAILED` - `deleteblobcase.js` - added hash candidate validation for raw/encoded `casefolderID` - added explicit catch-path contract: `DELETE_BLOB_CASE_FAILED` - `deleteblobrep.js` - added hash candidate validation for encoded/raw `casefolderID` + `repfile` - added explicit catch-path contract: `DELETE_BLOB_REP_FAILED` - Phase21 tests expanded (`file-handler-contract.test.cjs`): - encoded hash-variant acceptance cases for all three delete routes - explicit dependency-failure contract assertions for all three delete routes Validation: - `node tests/phase21/file-handler-contract.test.cjs` -> pass (23/23) - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 23/23 - email-handler: 12/12 - endpoint-handler: 149/149 Follow-ups: - Optional next slice: apply same bounded hash-canonicalization parity to remaining high-sensitivity file routes where mixed encoded/raw callers may exist (`getbloblist`, `getprogressobjblob`) and add regression cases to phase21. --- ### CL-007: TASK22224 getrepsblob stability hotfix after delete representation flow date: 2026-03-23 author: Cline scope: `actions/azurestorage.js` (`getRepsBlobs`), `tests/phase21/file-handler-contract.test.cjs` type: change rationale: Resolve reported runtime 400 (`GET_REPS_BLOB_FAILED`) after delete representation actions, caused by stale soft-deleted blob tag hits during representation blob enumeration. impact: Prevents transient/stale Azure tag index entries from breaking representation retrieval, improving reliability of post-delete refresh without relaxing route security contracts. status: completed Summary: - Hardened `getRepsBlobs(containerName)` in `actions/azurestorage.js`: - fixed async misuse (`blobClient.getProperties().contentLength` without await) - added existence/property guard with explicit `await blobClient.getProperties()` - skips 404s (soft-deleted/stale tag index results) instead of throwing - preserves behavior for non-404 failures (rethrow for proper error visibility) - kept existing `_rep.json`/`undefined` name filtering intact - Added phase21 contract coverage for `getrepsblob` route: - success payload contract test - dependency failure contract test (`GET_REPS_BLOB_FAILED`) Validation: - `node tests/phase21/file-handler-contract.test.cjs` -> pass (25/25) - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 25/25 - email-handler: 12/12 - endpoint-handler: 149/149 Follow-ups: - Optional: add the same stale-tag existence guard pattern to any remaining Azure tag-list readers that still consume `findBlobsByTags` results without property existence verification. --- ### CL-008: TASK22224 awaiting-submission route resilience parity hardening date: 2026-03-23 author: Cline scope: `pages/api/file/getawaitingsubmissionfromblob.js`, `tests/phase21/file-handler-contract.test.cjs` type: change rationale: Add explicit catch-path contract parity for awaiting-submission blob retrieval route so unexpected dependency failures return consistent, actionable error envelopes. impact: Improves reliability/diagnostics for post-delete case refresh and aligns file-route error handling style without changing success payload contract or hash verification behavior. status: completed Summary: - Refactored `getawaitingsubmissionfromblob` handler to structured `try/catch` flow. - Preserved existing guard behavior: - `MISSING_REQUIRED_QUERY` for missing container/hash - `INVALID_HASH` for signature mismatch - Added explicit dependency failure contract: - `GET_AWAITING_SUBMISSION_BLOB_FAILED` (400) - message: `Failed to retrieve awaiting submission blobs` - Added phase21 coverage for this route: - success payload pass-through contract - dependency failure contract assertion Validation: - `node tests/phase21/file-handler-contract.test.cjs` -> pass (27/27) - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 27/27 - email-handler: 12/12 - endpoint-handler: 149/149 Follow-ups: - Optional parity sweep: apply the same explicit catch-path contract pattern to remaining file routes that still rely on implicit promise-chain errors. --- ### CL-009: TASK22224 proxy-route resilience and encoding parity bundle date: 2026-03-23 author: Cline scope: `pages/api/file/{getbloblistproxy,getrepsblobproxy,getawaitingsubmissionfromblobproxy,createappealcompletemessageproxy_api}.js`, `tests/phase21/file-handler-contract.test.cjs` type: change rationale: Continue larger-slice hardening by aligning proxy handlers with explicit async error handling and safer encoded upstream query forwarding for hash-based downstream calls. impact: Improves proxy reliability and compatibility for encoded query values while preserving existing proxy error contracts and response behavior. status: completed Summary: - `getbloblistproxy.js` - converted `.then/.catch` chain to explicit `try/catch` - encoded forwarded `container` and `casefolderID` query values - preserved error contract: `GET_BLOB_LIST_PROXY_FAILED` - `getrepsblobproxy.js` - converted `.then/.catch` chain to explicit `try/catch` - encoded forwarded `container` - preserved error contract: `GET_REPS_BLOB_PROXY_FAILED` - `getawaitingsubmissionfromblobproxy.js` - converted `.then/.catch` chain to explicit `try/catch` - preserved error contract: `GET_AWAITING_SUBMISSION_PROXY_FAILED` - `createappealcompletemessageproxy_api.js` - converted `.then/.catch` chain to explicit `try/catch` - encoded forwarded `container` and `tempcaseref` - preserved error contract: `CREATE_APPEAL_COMPLETE_MESSAGE_PROXY_FAILED` - Phase21 tests expanded for proxy paths: - getbloblistproxy success + dependency failure - getrepsblobproxy success - getawaitingsubmissionfromblobproxy dependency failure - createappealcompletemessageproxy dependency failure Validation: - `node tests/phase21/file-handler-contract.test.cjs` -> pass (46/46) - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 46/46 - email-handler: 12/12 - endpoint-handler: 149/149 Follow-ups: - Optional next big slice: bring remaining proxy/message routes using raw axios promise chains (`createcaseinvolvement_api.js`, `createrepinvolvement_api.js`, `updatecase_api.js`) onto the same async/await + explicit contract pattern. --- ### CL-010: TASK22224 involvement/update route async contract hardening bundle date: 2026-03-23 author: Cline scope: `pages/api/file/{createcaseinvolvement_api,createrepinvolvement_api,updatecase_api}.js`, `tests/phase21/file-handler-contract.test.cjs` type: change rationale: Execute the next requested slice by modernizing remaining relay-backed involvement/update handlers that still used axios promise chains and legacy dead imports. impact: Improves reliability/readability and preserves existing response contracts, including 412 "record exists" semantics for involvement creation flows. status: completed Summary: - `createcaseinvolvement_api.js` - removed unused `CryptoJS` import - refactored axios `.then/.catch` to explicit `try/catch` - preserved conflict behavior: status 412 -> success `{ record: "exists" }` - preserved failure contract: `CREATE_CASE_INVOLVEMENT_FAILED` - `createrepinvolvement_api.js` - removed unused `CryptoJS` import - refactored axios `.then/.catch` to explicit `try/catch` - preserved conflict behavior: status 412 -> success `{ record: "exists" }` - preserved failure contract: `CREATE_REP_INVOLVEMENT_FAILED` - `updatecase_api.js` - removed unused `CryptoJS` import - refactored axios `.then/.catch` to explicit `try/catch` - preserved failure contract: `UPDATE_CASE_FAILED` - Phase21 tests expanded: - createcaseinvolvement 412 conflict success contract - createrepinvolvement dependency failure contract - updatecase dependency failure contract Validation: - `node tests/phase21/file-handler-contract.test.cjs` -> pass (49/49) - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 49/49 - email-handler: 12/12 - endpoint-handler: 149/149 Follow-ups: - Optional: apply equivalent modernization to any remaining relay-backed handlers outside `pages/api/file/` that still use raw axios promise chains and have no explicit phase21 contract assertions. --- ### CL-011: TASK22224 aggressive non-file bundle (email/admin/endpoint parity) date: 2026-03-23 author: Cline scope: `pages/api/email/{getmailinglist,getcaseref,notify}.js`, `pages/api/admin/{getnewappeals_api,getlatestdocuments_api}.js`, `pages/api/endpoint/getportallogin_api.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Execute requested aggressive bundling for remaining non-file modernization/parity candidates: remove legacy promise chains and improve hash compatibility on login endpoint while preserving existing contracts. impact: Improves consistency and resilience across email/admin/endpoint routes with no contract regressions; adds encoded hash-variant compatibility for portal login hash checks. status: completed Summary: - `pages/api/email/getmailinglist.js` - converted axios `.then/.catch` to `try/catch` - preserved flattening behavior and error contract `MAILING_LIST_FETCH_FAILED` - `pages/api/email/getcaseref.js` - converted axios `.then/.catch` to `try/catch` - preserved flattening behavior and error contract `CASE_REF_FETCH_FAILED` - `pages/api/email/notify.js` - converted notify client `.then/.catch` to `try/catch` - preserved success payload and error contract `EMAIL_NOTIFY_FAILED` - `pages/api/admin/getnewappeals_api.js` - removed unused `CryptoJS` import - converted axios `.then/.catch` to `try/catch` - preserved `@odata.nextLink` normalization and error contract `ADMIN_NEW_APPEALS_FETCH_FAILED` - `pages/api/admin/getlatestdocuments_api.js` - converted axios `.then/.catch` to `try/catch` - preserved flatten/enrich behavior and error contract `ADMIN_LATEST_DOCS_FETCH_FAILED` - `pages/api/endpoint/getportallogin_api.js` - retained required query/hash guards - expanded hash validation to accept raw + encoded `emailAddress` query-path candidates - preserved error contract `PORTAL_LOGIN_FETCH_FAILED` - phase21 endpoint tests expanded: - `getportallogin` encoded hash variant success path - `getnewappeals_api` catch contract - `getlatestdocuments_api` catch contract Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 49/49 - email-handler: 12/12 - endpoint-handler: 152/152 Follow-ups: - Remaining major modernization candidate is `pages/api/file/generateappealpdf.js` (+ optional `pages/api/file/generatepdf.js`) if we continue final closure slices. --- ### CL-012: TASK22224 generatepdf/generateappealpdf async hardening slice date: 2026-03-23 author: Cline scope: `pages/api/file/{generateappealpdf,generatepdf}.js`, `tests/phase21/file-handler-contract.test.cjs` type: change rationale: Execute next requested slice to modernize remaining file PDF-generation handlers still using promise chains, while preserving existing hash/response behavior. impact: Improves maintainability and error-path consistency for PDF generation routes; phase21 coverage now includes explicit failure contracts for both handlers. status: completed Summary: - `pages/api/file/generateappealpdf.js` - converted mixed promise-chain flow to `async/await` + `try/catch` - preserved existing guard contracts: `MISSING_REQUIRED_QUERY`, `INVALID_HASH` - preserved generation failure contract: `GENERATE_APPEAL_PDF_FAILED` - replaced JSX render call with `React.createElement(...)` compatibility form used by test loader - `pages/api/file/generatepdf.js` - converted create/upload promise-chain to `async/await` + `try/catch` - preserved existing guard contracts: `HASH_REQUIRED`, `INVALID_HASH` - preserved generation failure contract: `GENERATE_PDF_FAILED` - replaced JSX render call with `React.createElement(...)` compatibility form used by test loader - phase21 file tests expanded: - `generatepdf` catch-path contract (`GENERATE_PDF_FAILED`) - `generateappealpdf` catch-path contract (`GENERATE_APPEAL_PDF_FAILED`) Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 51/51 - email-handler: 12/12 - endpoint-handler: 152/152 Follow-ups: - Remaining optional cleanup in these handlers is dead import/unused local pruning (non-behavioral) if we want a final low-risk tidy pass. --- ### CL-013: TASK22224 completion-message route parity closure slice date: 2026-03-24 author: Cline scope: `pages/api/file/createappealcompletemessage_api.js`, `tests/phase21/file-handler-contract.test.cjs` type: change rationale: Continue next requested slice by closing the final promise-chain parity outlier in file completion-message flow and strengthening phase21 contract coverage. impact: Improves maintainability and async error hygiene while preserving route behavior and existing error contracts. status: completed Summary: - `pages/api/file/createappealcompletemessage_api.js` - replaced inline `.catch(...)` on fire-and-forget `updateAccount(...)` with explicit async IIFE + `try/catch` and `void` invocation - preserved non-blocking behavior and logging semantics for account-update failure path - preserved primary route contracts and success payload (`{ status: "success" }`) - phase21 file contract tests expanded: - success path for encoded hash candidate on `createappealcompletemessage_api` - dependency-failure contract assertion for `CREATE_APPEAL_COMPLETE_MESSAGE_FAILED` Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 Follow-ups: - Optional final low-risk tidy sweep: remove dead imports/unused locals in legacy file handlers now that contract hardening stream is functionally complete. --- ### CL-014: TASK22224 pdf render compatibility tidy slice date: 2026-03-24 author: Cline scope: `pages/api/file/{generatepdf,generateappealpdf}.js`, `tests/phase21/file-handler-contract.test.cjs` type: change rationale: Apply a low-risk compatibility tidy so PDF render invocation remains stable across runtime and contract-test VM contexts. impact: Keeps functional behavior unchanged while reducing test/runtime mismatch risk in render path setup. status: completed Summary: - `pages/api/file/generatepdf.js` - switched render call input from `React.createElement(MyDocument, ...)` to direct `MyDocument(...)` invocation in `ReactPDF.renderToStream(...)` - `pages/api/file/generateappealpdf.js` - switched render call input from `React.createElement(MyDocument, ...)` to direct `MyDocument(...)` invocation in `ReactPDF.renderToStream(...)` - `tests/phase21/file-handler-contract.test.cjs` - added `Buffer` injection for `generatepdf` catch-path test harness to align VM context expectations Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 Follow-ups: - Optional: dead import cleanup (`Document/Page/Text/View/StyleSheet/PDFViewer`, `middleware`, `nextConnect`, `fs`, etc.) can be done in a dedicated non-behavioral hygiene PR. --- ### CL-015: TASK22224 pdf handler dead-code hygiene slice date: 2026-03-24 author: Cline scope: `pages/api/file/{generatepdf,generateappealpdf}.js` type: change rationale: Execute the requested next low-risk slice by removing dead imports and unused locals in recently hardened PDF handlers. impact: Non-behavioral maintainability cleanup; reduces lint noise and future edit risk while preserving existing contracts. status: completed Summary: - `pages/api/file/generatepdf.js` - pruned unused Azure storage imports, leaving only `createRepPDFBlob` - pruned unused `@react-pdf/renderer` named imports - removed unused imports (`middleware`, `nextConnect`, `fs`) - removed unused locals (`casefolderID`, `representationType`, `repRaiser`, `localeSelect`, `repCapacity`, `repType`) - `pages/api/file/generateappealpdf.js` - pruned unused Azure storage imports to only required functions - pruned unused `@react-pdf/renderer` named imports - removed unused imports (`middleware`, `nextConnect`, `fs`, `path`, unused pdf templates) - removed unused local (`caseRef`) Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 Follow-ups: - Optional: run full repo lint in a separate pass for broader non-slice hygiene now that targeted contract suite is stable. --- ### CL-016: TASK22224 documents download contract slice date: 2026-03-24 author: Cline scope: `pages/api/documents/download/[id].js`, `tests/phase21/{documents-handler-contract,api-contract-slice1}.test.cjs` type: change rationale: Execute next aggressive slice by standardizing document download guard behavior and bringing the route under phase21 contract coverage. impact: Improves reliability on invalid input and relay-failure paths while preserving existing user-visible fallback behavior (`/filenotavailable`) for download failures. status: completed Summary: - `pages/api/documents/download/[id].js` - added explicit required-query guard for `id` and `hash` - unified fallback redirect path via constant (`/filenotavailable`) - preserved streaming download behavior and retry flow - added `tests/phase21/documents-handler-contract.test.cjs` covering: - missing query -> redirect contract - success -> attachment/content-type headers + stream pipe contract - relay failure -> redirect contract - updated combined runner (`tests/phase21/api-contract-slice1.test.cjs`) to include documents handler contract suite Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 - documents-handler: 3/3 Follow-ups: - Optional future hardening: migrate documents route onto shared `respondError/respondSuccess` envelope if product requirements allow replacing redirect-style fallback. --- ### CL-017: TASK22224 endpoint legacy-comment hygiene slice date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{createwatchedcases_api,getadvancedsearchpaged_api}.js` type: change rationale: Complete second requested slice with low-risk maintainability cleanup by removing large obsolete commented legacy handler blocks. impact: Non-behavioral cleanup only; improves readability and reduces maintenance noise with no runtime contract changes. status: completed Summary: - `createwatchedcases_api.js` - removed obsolete commented promise-chain implementation block - `getadvancedsearchpaged_api.js` - removed obsolete commented legacy implementation block retained below active handler Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 - documents-handler: 3/3 Follow-ups: - Optional further hygiene pass can target remaining oversized commented historical sections in non-sensitive handlers. --- ### CL-018: TASK22224 nextauth notify micro-refactor date: 2026-03-24 author: Cline scope: `pages/api/auth/[...nextauth].js` type: change rationale: Execute the explicitly approved auth micro-slice by replacing inline promise `.catch(...)` with explicit `try/catch` while preserving existing auth behavior. impact: Auth-sensitive non-functional refactor only; keeps current sign-in flow, template/locale routing, and error-handling semantics unchanged. status: completed Summary: - `pages/api/auth/[...nextauth].js` - replaced: - `await notifyClient.sendEmail(...).catch((error) => consoleLogger(error))` - with explicit: - `try { await notifyClient.sendEmail(...) } catch (error) { consoleLogger(error) }` - preserved behavior contracts: - Notify failures are still logged and do not throw through auth handler - no changes to callback URL construction, locale/template selection, NextAuth options, session/cookies/pages config Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 - documents-handler: 3/3 Follow-ups: - Optional future auth hygiene (separate guarded slice): replace verbose auth `console.log` diagnostics with structured logger usage once production logging requirements are confirmed. --- ### CL-019: TASK22229 P2-S1 relay forwarding pilot (proxy endpoint cluster) date: 2026-03-24 author: Cline scope: `pages/api/middleware/relayForwarding.js`, `pages/api/endpoint/{getwatchedcasesproxy_api,getmyrepresentationsproxy_api,getrepresentationsproxy_api,getawaitingsubmissionproxy_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Start Priority-2 by piloting a shared relay forwarding helper on a bounded proxy endpoint cluster to reduce duplicated token/hash/header/axios boilerplate while preserving endpoint contracts. impact: Maintainability and consistency improvement with no intended behavioral contract changes; error code/status/message and success payload contracts remain unchanged for migrated endpoints. status: completed Summary: - Added shared relay helper: - `pages/api/middleware/relayForwarding.js` - exports `relayGet({ queryUrl, res, errorResponse, transformData })` - centralizes token fetch, relay URL + hash composition, `azureHeaders`, GET execution, success/error response handling, and logging - Migrated pilot endpoint cluster to `relayGet`: - `getwatchedcasesproxy_api.js` (with existing payload transform preserved) - `getmyrepresentationsproxy_api.js` - `getrepresentationsproxy_api.js` - `getawaitingsubmissionproxy_api.js` (with existing payload transform preserved) - Updated endpoint contract tests to mock `relayGet` for migrated routes while preserving existing assertions. Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 - documents-handler: 3/3 Follow-ups: - P2-S2 rollout: migrate the next relay-heavy endpoint batch onto `relayGet`/shared forwarding utility pattern. - P2-S3 hardening: add shared timeout/retry config and redacted structured relay error logging policy. --- ### CL-020: TASK22229 P2-S2 Batch 1 (account/login relay GET cluster) date: 2026-03-24 author: Cline scope: `pages/api/middleware/relayForwarding.js`, `pages/api/endpoint/{getaccounts_api,getemailaccountcheck_api,getpreferredlanguage_api,getlogin_api,getpersonalaccount_api,getportalloginproxy_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Deliver first P2-S2 batch as a dedicated commit by migrating a bounded account/login endpoint cluster onto shared `relayGet` while preserving response contracts. impact: Reduced relay boilerplate and improved consistency with no intended endpoint contract changes. status: completed Summary: - Extended `relayGet` to support optional `requestOptionsBuilder` for handlers requiring paged header variants. - Migrated Batch 1 endpoints to `relayGet`: - `getaccounts_api.js` - `getemailaccountcheck_api.js` - `getpreferredlanguage_api.js` - `getlogin_api.js` (uses `azureHeadersPaged` via `requestOptionsBuilder`) - `getpersonalaccount_api.js` - `getportalloginproxy_api.js` (uses `azureHeadersPaged` via `requestOptionsBuilder`) - Updated phase21 endpoint contract tests to mock `relayGet` for migrated handlers, preserving existing guard/catch/success assertions. Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 - documents-handler: 3/3 Follow-ups: - Continue P2-S2 with Batch 2 as next dedicated commit on this same branch. --- ### CL-021: TASK22229 P2-S2 Batch 2 (my-portal + representation relay GET cluster) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getmycases_api,getmyrepresentations_api,getwatchedcases_api,getawaitingsubmission_api,getrepresentations_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Deliver second P2-S2 commit by migrating the next bounded portal/representation GET endpoint cluster onto shared `relayGet` while preserving route contracts. impact: Reduced duplicated relay boilerplate and aligned forwarding behavior with no intended response contract changes. status: completed Summary: - Migrated Batch 2 endpoints to `relayGet`: - `getmycases_api.js` (preserved title mapping transform) - `getmyrepresentations_api.js` - `getwatchedcases_api.js` (preserved watched-case projection transform) - `getawaitingsubmission_api.js` (preserved title mapping transform) - `getrepresentations_api.js` - Updated phase21 endpoint contract tests for migrated handlers by mocking `relayGet` in guard/catch test paths. Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 - documents-handler: 3/3 Follow-ups: - Continue P2-S2 with Batch 3 as the next dedicated commit on this branch. --- ### CL-022: TASK22229 P2-S2 Batch 3 (case/event relay GET cluster) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getcase_api,getcasebyid_api,getincidentbyid_api,getsipsevents_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Deliver third P2-S2 commit by migrating an additional bounded case/event endpoint cluster onto shared `relayGet` while preserving route contracts. impact: Further relay boilerplate reduction and consistent forwarding behavior with no intended contract changes. status: completed Summary: - Migrated Batch 3 endpoints to `relayGet`: - `getcase_api.js` (preserved `@odata.nextLink` normalization) - `getcasebyid_api.js` (preserved `@odata.nextLink` normalization and array-wrapped success payload) - `getincidentbyid_api.js` - `getsipsevents_api.js` - Updated phase21 endpoint contract tests to mock `relayGet` for migrated handlers in guard/catch paths. Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 152/152 - documents-handler: 3/3 Follow-ups: - Continue P2-S2 with next bounded batch (e.g. search/listing cluster) as a separate commit if required. --- ### CL-023: TASK22229 P2-S2 Batch 6 (profile/form/document-history/portal-module relay GET cluster) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getpersonalaccount_api,getformdata_api,getsearchdocumenthistory_api,getsearchdocumenthistorypaged_api,getportalmoduledetails_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Execute requested Batch 6 by migrating the next bounded set of read-only endpoint handlers to shared `relayGet` while preserving existing request validation and response/error contracts. impact: Reduced endpoint relay boilerplate and improved consistency; no intended behavior contract changes. status: completed Summary: - Migrated Batch 6 endpoints to shared `relayGet`: - `getpersonalaccount_api.js` - `getformdata_api.js` - `getsearchdocumenthistory_api.js` (uses `requestOptionsBuilder` with `azureHeadersPaged`) - `getsearchdocumenthistorypaged_api.js` (uses `requestOptionsBuilder` with `azureHeadersPaged`) - `getportalmoduledetails_api.js` - Preserved all existing required-query validation guards and existing error codes/messages. - Updated Phase 21 endpoint contract tests to inject `relayGet` mocks for migrated handlers (validation path, catch path, and success path where applicable). Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded batch: migrate remaining legacy relay GET handlers in advanced/basic search-document/detail clusters that still use direct axios relay patterns. --- ### CL-024: TASK22229 P2-S2 Batch 7 (search-document + portal-proxy relay GET cluster) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getportalmoduledetailsproxy_api,getsearchdocumentTypes_api,getsearchdocumentdetails_api,getsearchdocumentdetailspaged_api,getappealpdfdocuments_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Continue P2-S2 in bounded commits by migrating a coherent search-document/portal-proxy GET cluster onto shared relay forwarding while preserving existing validation, transforms, and error contracts. impact: Reduced duplicate relay plumbing and improved consistency in search-document handlers; no intended API contract changes. status: completed Summary: - Migrated Batch 7 endpoints to shared `relayGet`: - `getportalmoduledetailsproxy_api.js` - `getsearchdocumentTypes_api.js` - `getsearchdocumentdetails_api.js` - `getsearchdocumentdetailspaged_api.js` - `getappealpdfdocuments_api.js` - Preserved existing guard behavior and error response contracts. - Preserved endpoint-specific transform behavior via `transformData`, including: - grouped search-document type payloads - document hashlink enrichment and published-date normalization - `@odata.nextLink` normalization where present - appeal PDF document name projection - Updated phase21 endpoint tests to mock `relayGet` for migrated handlers in validation/catch/success paths as applicable. Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Continue with next bounded P2-S2 batch from remaining legacy GET endpoints (e.g., advanced/basic paged search-detail clusters and related non-migrated proxies). --- ### CL-025: TASK22229 P2-S2 Batch 8 (basic search details + DNS details relay GET cluster) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getbasicsearchpaged_api,getbasicsearchdetails_api,getbasicsearchdetailspaged_api,getbasicdnssearchdetails_api,getbasicdnssearchdetailspaged_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Continue the P2-S2 relay migration using bounded commits by moving the remaining basic-search-details and DNS-details GET handlers to shared `relayGet`, preserving existing guards and response contracts. impact: Reduced duplicated relay plumbing and more consistent forwarding behavior across search-detail handlers; no intended API contract changes. status: completed Summary: - Migrated Batch 8 endpoints to shared `relayGet`: - `getbasicsearchpaged_api.js` - `getbasicsearchdetails_api.js` - `getbasicsearchdetailspaged_api.js` - `getbasicdnssearchdetails_api.js` - `getbasicdnssearchdetailspaged_api.js` - Preserved existing validation guards and error contracts. - Preserved existing endpoint-specific transforms: - `@odata.nextLink` normalization in paged responses - flattened ticketnumber enrichment for search detail handlers - Updated phase21 endpoint contract tests to inject `relayGet` mocks for migrated handlers in validation and catch-path tests. Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Continue P2-S2 with next bounded batch from remaining legacy GET endpoints (currently: `createwatchedcases_api`, `deletewatchedcasesproxy_api`, `getadvancedsearch_api`, `getadvancedsearchpaged_api`, `getappealid_api`, `getbasicdnssearchpaged_api`, `getbasicpartsaveddetails_api`, `getbasicsearch_by_address_api`, `getbasicsearch_by_lparref_api`, `getdnscoords_api`, `getdnslist_api`, `getmylpacases_api`, `getportallogin_api`). --- ### CL-026: TASK22229 P2-S2 Batch 9 (appeal-id + DNS list/paged + part-saved relay GET cluster) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getappealid_api,getbasicdnssearchpaged_api,getbasicpartsaveddetails_api,getdnslist_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Continue bounded P2-S2 relay migration by moving another coherent set of read-only handlers to shared `relayGet`, preserving existing guards, transforms, and error contracts. impact: Reduced duplicated relay plumbing and improved consistency for DNS list/paged and appeal detail lookup endpoints; no intended API contract changes. status: completed Summary: - Migrated Batch 9 endpoints to shared `relayGet`: - `getappealid_api.js` - `getbasicdnssearchpaged_api.js` - `getbasicpartsaveddetails_api.js` - `getdnslist_api.js` - Preserved existing input validation guards and endpoint-specific error contracts. - Preserved endpoint-specific transform behavior (`@odata.nextLink` normalization in DNS list/paged handlers). - Updated phase21 endpoint contract tests to inject `relayGet` mocks for these migrated handlers in guard and catch-path assertions. Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Continue P2-S2 with next bounded batch from remaining legacy relay GET endpoints (`createwatchedcases_api`, `deletewatchedcasesproxy_api`, `getadvancedsearch_api`, `getadvancedsearchpaged_api`, `getbasicsearch_by_address_api`, `getbasicsearch_by_lparref_api`, `getdnscoords_api`, `getmylpacases_api`, `getportallogin_api`). --- ### CL-027: TASK22229 P2-S2 Batch 10 (portal login + my LPA cases relay GET pair) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getportallogin_api,getmylpacases_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Continue bounded relay migration by moving two remaining high-use portal retrieval endpoints to shared `relayGet` while preserving existing hash/lookup guards and response contracts. impact: Further relay boilerplate reduction and consistent forwarding behavior in portal login/LPA case retrieval flows; no intended API contract changes. status: completed Summary: - Migrated Batch 10 endpoints to shared `relayGet`: - `getportallogin_api.js` (preserved hash validation guard and error contract) - `getmylpacases_api.js` (preserved LPA lookup/404 guard and title transform) - Preserved endpoint-specific behavior: - `getportallogin_api`: raw + encoded hash candidate validation before relay call - `getmylpacases_api`: JSONPath LPA lookup with `LPA_NOT_FOUND` handling and `pinswg_title` enrichment transform - Updated phase21 endpoint contract tests to inject `relayGet` mocks for migrated handlers in validation/catch/success paths. Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Continue P2-S2 with the remaining legacy relay GET candidates (`createwatchedcases_api`, `deletewatchedcasesproxy_api`, `getadvancedsearch_api`, `getadvancedsearchpaged_api`, `getbasicsearch_by_address_api`, `getbasicsearch_by_lparref_api`, `getdnscoords_api`). --- ### CL-028: TASK22229 P2-S2 Batch 11 (advanced-search-paged relay GET) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/getadvancedsearchpaged_api.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Continue bounded relay migration by moving the remaining advanced-search paged GET handler to shared `relayGet` while preserving query validation and response contracts. impact: Reduced duplicated relay plumbing and aligned advanced paged search route with shared forwarding; no intended API contract changes. status: completed Summary: - Migrated `getadvancedsearchpaged_api.js` to shared `relayGet`. - Preserved existing guard behavior and error contracts: - `SEARCH_STRING_REQUIRED` - `ORDER_BY_REQUIRED` - `FIELD_SORT_REQUIRED` - `SHOW_NUMBER_OF_RECORDS_REQUIRED` - `INVALID_SEARCH_STRING` - `ADVANCED_SEARCH_PAGED_FETCH_FAILED` - Preserved endpoint-specific transform behavior (`@odata.nextLink` normalization via `transformData`). - Updated phase21 endpoint contract tests to inject `relayGet` mocks for `getadvancedsearchpaged_api` guard/catch assertions. Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Continue P2-S2 with remaining legacy relay GET candidates (`createwatchedcases_api`, `deletewatchedcasesproxy_api`, `getadvancedsearch_api`, `getbasicsearch_by_address_api`, `getbasicsearch_by_lparref_api`, `getdnscoords_api`). --- ### CL-029: TASK22229 P2-S2 Batch 12 (remaining relay GET candidates) date: 2026-03-24 author: Cline scope: `pages/api/middleware/relayForwarding.js`, `pages/api/endpoint/{createwatchedcases_api,deletewatchedcasesproxy_api,getadvancedsearch_api,getbasicsearch_by_address_api,getbasicsearch_by_lparref_api,getdnscoords_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Complete Batch 12 by migrating the remaining listed legacy relay GET candidates to shared forwarding helpers while preserving endpoint-specific validation, transforms, and error contracts. impact: Consolidated relay GET behavior and reduced endpoint-level relay boilerplate; no intended API contract changes. status: completed Summary: - Extended relay middleware with reusable helpers: - `relayGetData` now supports token reuse via `transformData` path - Added `forwardGetData` to support custom base URLs (used by proxy-to-local endpoint) while preserving hash behavior - Migrated remaining Batch 12 candidates: - `getadvancedsearch_api.js` -> `relayGet` + `relayGetData` for project-type enrichment loop - `getdnscoords_api.js` -> `relayGetData` for both DNS + SIPS source pulls - `getbasicsearch_by_lparref_api.js` -> `relayGetData` - `getbasicsearch_by_address_api.js` -> `relayGetData` for appeal-type and incident fetches - `deletewatchedcasesproxy_api.js` -> `forwardGetData` with `BASE_URL` - `createwatchedcases_api.js` -> `relayGetData` for record-exists pre-check (POST/PATCH upsert flow preserved) - Preserved endpoint-specific guard and error contracts (including status codes such as 500 for `BASIC_SEARCH_BY_ADDRESS_FETCH_FAILED`). - Updated phase21 endpoint contract tests for migrated handlers to mock `relayGetData` / `forwardGetData` where appropriate. Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Batch 12 completes the previously listed remaining P2-S2 relay GET candidates. --- ### CL-030: TASK22236 P2-S3 relay forwarding hardening (timeouts, retries, structured redacted logs) date: 2026-03-24 author: Cline scope: `pages/api/middleware/relayForwarding.js`, `tests/phase21/relay-forwarding-hardening.test.cjs` type: change rationale: Begin P2-S3 by hardening shared relay forwarding behavior with bounded timeout/retry controls and structured redacted operational logging, reducing transient failure impact while preserving endpoint contracts. impact: Improves resilience/observability for relay GET traffic; endpoint success/error contracts remain unchanged because caller handlers still manage response envelopes. status: completed Summary: - Hardened `forwardGetData` in `relayForwarding.js` with: - configurable timeout (`RELAY_TIMEOUT_MS`, default 8000ms) - bounded retries (`RELAY_RETRY_MAX`, default 2) - exponential backoff with cap (`RELAY_RETRY_BASE_DELAY_MS`, `RELAY_RETRY_MAX_DELAY_MS`) - retry eligibility for transient statuses/codes (`408/429/5xx`, selected network timeout/reset codes) - Added structured, redacted operational relay logs: - `relay_request_retrying` - `relay_request_failed` - Preserved compatibility behaviors: - existing token/header/hash handling - optional `appendHash` and custom `requestOptionsBuilder` - endpoint-level `relayGet` error response semantics - Added focused Phase 21 hardening tests: - retries on retryable status and succeeds - does not retry non-retryable status - applies timeout and respects `appendHash=false` Validation: - `node tests/phase21/relay-forwarding-hardening.test.cjs` -> pass (3/3) - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next hardening increment: introduce endpoint-specific retry overrides for write paths (if future non-GET use is introduced) to keep retry policy conservative by operation type. --- ### CL-031: TASK22236 P2-S3 Batch 2A policy tightening (retry classification, config clamping, log de-dup) date: 2026-03-24 author: Cline scope: `pages/api/middleware/relayForwarding.js`, `tests/phase21/relay-forwarding-hardening.test.cjs` type: change rationale: Execute P2-S3 Batch 2A by tightening relay retry policy and operational safety bounds while preventing duplicate error noise between relay-layer and endpoint-layer logging. impact: Stronger resilience and cleaner observability with no endpoint contract changes; retry behavior is now explicitly conservative for deterministic client/auth failures. status: completed Summary: - Updated relay retry policy: - explicitly non-retryable statuses: `400`, `401`, `403`, `404`, `422` - retries still allowed for transient classes (`408`, `429`, `5xx`) and selected transport error codes - any other explicit numeric HTTP status now treated as non-retryable by default - Added runtime-safe config clamping for relay knobs: - timeout clamped to `100..30000ms` - retries clamped to `0..4` - retry delays clamped to `0..5000ms` - both env-derived and per-call numeric overrides are sanitized - Reduced duplicate logging noise: - non-retry terminal relay failures are marked as already logged in middleware - `relayGet` catch now skips `consoleLogger` when relay layer has already emitted a structured log - Expanded relay hardening tests: - no retry on `401` - duplicate logging suppression path through `relayGet` - env-value clamping behavior for timeout bounds Validation: - `node tests/phase21/relay-forwarding-hardening.test.cjs` -> pass (6/6) - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Batch 2B: update memory/context docs with canonical relay hardening policy, env knobs, and rollback/tuning guidance. --- ### CL-032: TASK22239 governance + operational rollout playbook bundle (relay hardening) date: 2026-03-24 author: Cline scope: `context/runbook.md`, `context/integration-map.md`, `memory-bank/{change-log,decisions,patterns}.md` type: change rationale: Deliver a combined governance and operational rollout slice after P2-S3 code hardening so relay policy changes have explicit merge gates, smoke matrix coverage, and rollback/monitoring discipline. impact: Improves release safety and auditability for relay policy updates without changing runtime endpoint behavior. status: completed Summary: - Added a dedicated **Relay Hardening Rollout Playbook** section to `context/runbook.md` covering: - pre-merge governance gate checklist - non-prod smoke matrix for deterministic and transient failure classes - progressive rollout guidance - Day 1/Day 3 monitoring checks - fast mitigation/rollback sequence - Added relay policy governance references in architecture/integration context docs to make rollout checks discoverable for future contributors. - Recorded governance baseline updates in memory-bank: - decision entry for relay policy-change governance gate - reusable pattern entry for required rollout/smoke/rollback workflow Validation: - Documentation consistency review across `context/runbook.md`, `context/integration-map.md`, and memory-bank entries. Follow-ups: - Optional next iteration: add a PR template block in Azure DevOps mirroring the runbook governance gate checklist. --- ### CL-033: TASK22242 relay telemetry enrichment (lifecycle events + correlation fields) date: 2026-03-24 author: Cline scope: `pages/api/middleware/relayForwarding.js`, `tests/phase21/relay-forwarding-hardening.test.cjs` type: change rationale: Add richer relay observability so operations can correlate retries and outcomes per request and track latency/status patterns without changing endpoint contracts. impact: Improves operational diagnostics and trend analysis for relay traffic while preserving existing API behavior. status: completed Summary: - Enriched relay middleware telemetry with request lifecycle events: - `relay_request_started` - `relay_request_retrying` - `relay_request_succeeded` - `relay_request_failed` - Added shared telemetry fields for correlation and analysis: - `relayRequestId` (per request correlation id) - `attemptsMade`, `retryCountUsed`, `remainingRetries` - `elapsedMs` - `statusClass` (`2xx/4xx/5xx` style buckets) - resolved runtime knobs included at start event - Kept existing retry policy and endpoint response contracts unchanged. - Expanded phase21 relay hardening tests to assert telemetry behavior: - started/retrying/succeeded event presence - failed event telemetry fields - stable `relayRequestId` across lifecycle events for one request Validation: - `node tests/phase21/relay-forwarding-hardening.test.cjs` -> pass (7/7) - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next step: map these lifecycle fields into central dashboards/alerts (retry rate, status-class distribution, p95 elapsedMs). --- ### CL-034: TASK22242 per-endpoint relay overrides + idempotency-aware retry gating date: 2026-03-24 author: Cline scope: `pages/api/middleware/relayForwarding.js`, `tests/phase21/relay-forwarding-hardening.test.cjs` type: change rationale: Deliver the next functional relay enhancement by enabling route-level retry tuning while adding safe-by-default retry gating for non-idempotent methods. impact: Improves control and safety of relay retries without breaking existing endpoint contracts. status: completed Summary: - Added **relay policy override support** (`relayPolicy`) to shared relay helpers (`relayGet`, `relayGetData`, `forwardGetData`): - per-call override of `timeoutMs`, `maxRetries`, `retryBaseDelayMs`, `retryMaxDelayMs` - optional method override via `relayPolicy.method` - Added **idempotency-aware retry gating scaffolding**: - retries allowed by default only for idempotent methods (`GET`, `HEAD`, `OPTIONS`) - non-idempotent retry behavior controlled by: - env flag `RELAY_ALLOW_NON_IDEMPOTENT_RETRIES` (default false) - per-call override `relayPolicy.allowNonIdempotentRetries` - Extended relay telemetry fields to include method and non-idempotent policy posture in start/failure/retry events. - Preserved existing route behavior: - existing GET endpoint flows continue to use retries per configured bounds - no endpoint response contract changes Validation: - `node tests/phase21/relay-forwarding-hardening.test.cjs` -> pass (10/10) - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Future non-GET relay adoption should explicitly opt in/out per route using `relayPolicy` and include targeted negative-path tests. --- ### CL-035: TASK22242 apply relayPolicy overrides across broader endpoint cluster date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getaccounts_api,getemailaccountcheck_api,getpreferredlanguage_api,getpersonalaccount_api,getlogin_api,getbasicsearch_api,getbasicsearchpaged_api,getadvancedsearch_api,getadvancedsearchpaged_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Expand practical adoption of per-endpoint relay policy tuning so high-traffic account/login/search handlers explicitly declare timeout/retry posture rather than relying only on global defaults. impact: Better operational control and predictable retry behavior per endpoint cluster, with no API contract changes. status: completed Summary: - Added explicit `relayPolicy` usage to a broader endpoint set: - account/login: `getaccounts`, `getemailaccountcheck`, `getpreferredlanguage`, `getpersonalaccount`, `getlogin` - search: `getbasicsearch`, `getbasicsearchpaged`, `getadvancedsearch`, `getadvancedsearchpaged` - Applied conservative policy profiles by flow: - login endpoint (`getlogin`): no retries (`maxRetries: 0`) and tighter timeout - account lookup endpoints: low retry posture (`maxRetries: 1`) - search endpoints: bounded retry posture (`maxRetries: 2`) for transient resilience - Kept method explicit as `GET` in policy for clarity and future-proofing. - Extended phase21 endpoint tests with relayPolicy propagation assertions: - `getaccounts` relayPolicy pass-through - `getlogin` strict relayPolicy pass-through - `getbasicsearchpaged` relayPolicy pass-through Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (155/155) - `node tests/phase21/relay-forwarding-hardening.test.cjs` -> pass (10/10) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next slice: apply relayPolicy declarations to remaining relayGet endpoints in coherent batches (portal module/documents/DNS groups) and standardize policy presets in one shared constants module. --- ### CL-036: TASK22242 portal-facing relayPolicy parity (login + module endpoints) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getportallogin_api,getportalloginproxy_api,getportalmoduledetails_api,getportalmoduledetailsproxy_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Complete the next practical relay policy rollout slice by bringing portal-facing login/module endpoints onto explicit per-endpoint timeout/retry posture. impact: Improves predictability and operational tuning for portal-facing relay GET flows without changing API contracts. status: completed Summary: - Added explicit `relayPolicy` for four portal-facing endpoints: - `getportallogin_api` -> strict/no-retry profile (`maxRetries: 0`, tighter timeout) - `getportalloginproxy_api` -> low-retry account lookup profile (`maxRetries: 1`) - `getportalmoduledetails_api` -> bounded read profile (`maxRetries: 2`) - `getportalmoduledetailsproxy_api` -> bounded read profile (`maxRetries: 2`) - Kept method explicit (`GET`) in each endpoint policy object. - Extended phase21 endpoint tests with relayPolicy propagation assertions for all four endpoints. Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (159/159) - `node tests/phase21/relay-forwarding-hardening.test.cjs` -> pass (10/10) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next slice: extract shared relay policy presets into constants to reduce duplication and enforce profile consistency across remaining relayGet endpoints. --- ### CL-037: TASK22242 portal/my-cases relayPolicy parity (my portal + representations) date: 2026-03-24 author: Cline scope: `pages/api/endpoint/{getmycases_api,getmyrepresentations_api,getwatchedcases_api,getawaitingsubmission_api,getrepresentations_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs` type: change rationale: Continue the branch-by-branch relay policy rollout by applying explicit policy posture to core my-portal retrieval endpoints. impact: Improves consistency and operational predictability of relay behavior for portal case/representation listing flows without changing endpoint contracts. status: completed Summary: - Added explicit `relayPolicy` declarations to: - `getmycases_api` - `getmyrepresentations_api` - `getwatchedcases_api` - `getawaitingsubmission_api` - `getrepresentations_api` - Applied bounded read profile across the batch: - `method: "GET"` - `timeoutMs: 8000` - `maxRetries: 2` - `retryBaseDelayMs: 150` - `retryMaxDelayMs: 800` - Extended phase21 endpoint contract tests with relayPolicy pass-through assertions for each endpoint. Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (164/164) - `node tests/phase21/relay-forwarding-hardening.test.cjs` -> pass (10/10) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next slice: extract shared relay policy presets into a constants module and reference them from all relayGet endpoints to reduce duplication. --- ### CL-038: TASK22242 P2-S3 closure slice — shared relay policy presets extraction date: 2026-03-24 author: Cline scope: `pages/api/middleware/relayPolicyPresets.js`, `pages/api/endpoint/{getaccounts_api,getemailaccountcheck_api,getpreferredlanguage_api,getpersonalaccount_api,getlogin_api,getportallogin_api,getportalloginproxy_api,getbasicsearch_api,getbasicsearchpaged_api,getadvancedsearch_api,getadvancedsearchpaged_api,getportalmoduledetails_api,getportalmoduledetailsproxy_api,getmycases_api,getmyrepresentations_api,getawaitingsubmission_api,getrepresentations_api,getwatchedcases_api}.js`, `tests/phase21/_shared.cjs` type: change rationale: Complete the planned P2-S3 final maintainability slice by centralizing repeated relay timeout/retry policy objects into shared presets used consistently across all targeted relayGet endpoints. impact: Eliminates duplicated policy literals, reduces drift risk, and preserves endpoint contracts/behavior by reusing equivalent policy values. status: completed Summary: - Added new middleware constants module: - `pages/api/middleware/relayPolicyPresets.js` - `RELAY_POLICY_STRICT_LOGIN` - `RELAY_POLICY_LOOKUP` - `RELAY_POLICY_BOUNDED_READ` - `RELAY_POLICY_SEARCH_PAGED` - Refactored 18 relayGet endpoints to import and use shared presets instead of inline `relayPolicy` object literals: - lookup profile: `getaccounts`, `getemailaccountcheck`, `getpreferredlanguage`, `getpersonalaccount`, `getportalloginproxy` - strict login profile: `getlogin`, `getportallogin` - bounded read profile: `getbasicsearch`, `getportalmoduledetails`, `getportalmoduledetailsproxy`, `getmycases`, `getmyrepresentations`, `getawaitingsubmission`, `getrepresentations`, `getwatchedcases` - search paged profile: `getbasicsearchpaged`, `getadvancedsearch`, `getadvancedsearchpaged` - Updated phase21 VM test harness (`tests/phase21/_shared.cjs`) to inject preset constants so endpoint contract tests continue to execute with import-stripped modules. Validation: - `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (164/164) - `node tests/phase21/relay-forwarding-hardening.test.cjs` -> pass (10/10) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - P2-S3 planned slices are now complete; no further mandatory relay policy rollout slices remain for this stream. --- ### CL-039: TASK22260 actions façade increment — shared relay client extraction date: 2026-03-25 author: Cline scope: `actions/clients/{relayClient,index}.js`, `actions/services/{accountDirectService,portalDirectService,documentDirectService}.js`, `actions/index.js`, `actions/clients/README.md` type: change rationale: Continue Priority 1 façade decomposition by extracting duplicated hash-signing relay helper logic into a dedicated client module while preserving existing service/public export contracts. impact: Reduces duplication and drift risk in security-sensitive relay signing helper logic without changing call-site behavior. status: completed Summary: - Added a new shared client wrapper: - `actions/clients/relayClient.js` exporting `buildHashedQueryUrl` - Added `actions/clients/index.js` barrel and exposed client exports via `actions/index.js`. - Updated direct services to consume shared relay client helper instead of duplicating local helper implementations: - `actions/services/accountDirectService.js` - `actions/services/portalDirectService.js` - `actions/services/documentDirectService.js` - Updated `actions/clients/README.md` to reflect the now-implemented relay client extraction and future incremental client split path. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - Verified no remaining duplicated local `buildHashedQueryUrl` definitions across `actions/services/*DirectService.js` Follow-ups: - Optional next TASK22260 increment: extract common axios invocation helpers into dedicated clients (`endpointClient`, `fileClient`, `notifyClient`) while keeping `actions/index.js` API stable. Addendum (same TASK22260 slice): - Added shared `endpointClient` with `getJson` and `requestJson` helpers (`actions/clients/endpointClient.js`) and exported it via `actions/clients/index.js`. - Migrated additional direct services to consume shared endpoint client helpers: - `actions/services/notifyDirectService.js` (POST via `requestJson`) - `actions/services/integrationDirectService.js` (POST via `requestJson`) - `actions/services/adminDirectService.js` (GET flows via `getJson`) - Updated `actions/clients/README.md` to include `endpointClient` in current extracted clients. --- ### CL-040: TASK22260 next slice — reference-data direct service endpointClient adoption date: 2026-03-25 author: Cline scope: `actions/services/referenceDataDirectService.js`, `actions/clients/README.md` type: change rationale: Continue the incremental façade/client adoption stream by migrating another bounded direct-service module to shared endpoint request helpers. impact: Reduces axios boilerplate and centralizes JSON extraction behavior for reference-data requests without changing public call signatures. status: completed Summary: - Migrated `actions/services/referenceDataDirectService.js` from direct `axios.get(...).then(res => res.data)` patterns to shared `getJson(...)` helper from `actions/clients/endpointClient`. - Preserved existing error behavior: - `logAndReturnEmptyValueErrorResponse` for appeals/project/LPA fetches - `consoleLogger` catch handling for form/mandatory/picklist/notice fetches - Updated `actions/clients/README.md` usage notes to include reference-data service reuse. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Next optional bounded slice: adopt `getJson`/`requestJson` for selected low-risk read paths in `searchDirectService` or `caseDirectService` while preserving per-function error semantics. --- ### CL-041: TASK22260 next slice — account direct service endpointClient adoption date: 2026-03-25 author: Cline scope: `actions/services/accountDirectService.js` type: change rationale: Continue incremental façade migration by moving account direct-service request plumbing onto shared endpoint client helpers while preserving existing error-return behavior contracts. impact: Reduces duplicated axios response extraction boilerplate and aligns account service request handling with the emerging client-layer pattern. status: completed Summary: - Refactored `actions/services/accountDirectService.js` to consume shared endpoint client helpers: - `getJson(...)` for GET requests - `requestJson(...)` for config-based POST requests - Kept existing relay hash-signing behavior unchanged via `buildHashedQueryUrl` from `relayClient`. - Preserved existing catch-path semantics, including: - logging with `consoleLogger` - returning `JSON.stringify(error)` in portal login functions - returning `error.response` in preferred-language failure path Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: adopt endpoint client helpers in selected `portalDirectService` GET/POST helper paths while preserving delete/hash flow semantics. --- ### CL-042: TASK22260 next slice — portal direct service partial endpointClient adoption date: 2026-03-25 author: Cline scope: `actions/services/portalDirectService.js` type: change rationale: Continue phased client-layer adoption by migrating low-risk portal direct-service read/create paths to shared endpoint request helpers while leaving hash-sensitive delete/message flows unchanged. impact: Reduces duplicated axios response extraction on high-traffic portal retrieval paths and keeps hashed delete/message semantics stable. status: completed Summary: - Refactored selected `portalDirectService` functions to use shared endpoint client helpers: - `getJson(...)` for read/listing routes (`getMyCases`, `getMyInvolvements`, `getMyLPACases`, representations, watched, awaiting submission variants) - `requestJson(...)` for `createWatchedCases` - Preserved existing hash/delete/message flow implementations (`deleteMyRepresentations`, `deleteWatchedCases`, completion message functions) using existing axios + relay signing behavior. - Preserved existing catch-path logging behavior for all migrated functions. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: migrate remaining non-hash POST helpers in `portalDirectService` (`setRepInvolvment`, `setCaseInvolvment`) to `requestJson` for full internal consistency. --- ### CL-043: TASK22260 next slice — portal involvement helper endpointClient completion date: 2026-03-25 author: Cline scope: `actions/services/portalDirectService.js` type: change rationale: Complete the next bounded internal-consistency slice by migrating remaining non-hash portal involvement POST helpers to shared endpoint client request plumbing. impact: Aligns portal service POST helper internals with established `requestJson` usage while preserving route semantics and error handling. status: completed Summary: - Migrated remaining portal involvement helper POST functions to shared endpoint client: - `setRepInvolvment` - `setCaseInvolvment` - Both now use `requestJson(config)` while preserving existing payload shape, endpoint URLs, and catch-path logging behavior. - No changes made to hash-sensitive delete/message pathways. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: begin selective `requestJson` adoption for remaining config-based calls in `documentDirectService` where hash flow is already centralized. --- ### CL-044: TASK22260 next slice — document direct service low-risk getJson adoption date: 2026-03-25 author: Cline scope: `actions/services/documentDirectService.js` type: change rationale: Continue incremental façade/client rollout by migrating low-risk document service GET wrappers that already return JSON and do not alter hash-signing semantics. impact: Reduces duplicated axios `.get(...).then(res => res.data)` boilerplate and aligns document retrieval helpers with shared endpoint client usage. status: completed Summary: - Added `getJson` usage in selected document service helpers: - `getRepsFromBlobProxy` - `getAwaitingSubmissionFromBlobProxy` - `getFilesFromBlobproxy` - `getFilesFromBlobHashed` - `getProgressFromBlob` - `createContainerProxy` - Preserved existing behavior contracts: - same query composition and hash query fragments - same catch-path logging and return conventions (including JSON string return in `createContainerProxy` error path) - Left hash-sensitive delete/upload/generation flows unchanged in this slice. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: migrate selected `requestJson`-eligible upload/generation helpers in `documentDirectService` (non-download paths) while preserving multipart/blob behavior. --- ### CL-045: TASK22260 next slice — document direct service requestJson adoption (uploads + PDF generation) date: 2026-03-25 author: Cline scope: `actions/services/documentDirectService.js` type: change rationale: Continue bounded client migration by moving config-based multipart/PDF POST helpers in document service to shared `requestJson` while preserving hashed URL generation and responseType behavior. impact: Reduces repeated axios config execution boilerplate and aligns document POST helper internals with shared endpoint client conventions. status: completed Summary: - Migrated selected config-based document helper flows from `axios(config)` + `res.data` to `requestJson(config)`: - `uploadFiles` - `uploadSingleFile` - `uploadRepFiles` - `generateRepPDF` - `generateAppealPDF` - Preserved behavior-critical aspects: - hashed URL creation via `buildHashedQueryUrl(...)` - multipart headers for upload flows - conditional `responseType: "blob"` for download PDF option paths - existing catch-path logging semantics - Left delete/download/hash-sensitive GET helpers unchanged in this slice. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: evaluate remaining legacy direct `axios.get(...).then(res.data)` helpers in `documentDirectService` (`getAwaitingSubmissionFromBlob`, `getRepsFromBlob`, `getFilesFromBlob`) for safe migration while preserving signed hash path behavior. --- ### CL-046: TASK22260 next slice — document direct service remaining signed GET helper migration date: 2026-03-25 author: Cline scope: `actions/services/documentDirectService.js` type: change rationale: Complete the remaining low-risk read helper migration in document service by replacing final direct `axios.get(...).then(res.data)` patterns with shared `getJson` while retaining hash/signature query construction. impact: Finishes consistency pass for JSON-returning document read helpers and reduces duplicated response extraction logic. status: completed Summary: - Migrated the remaining signed document read helpers to `getJson(...)`: - `getAwaitingSubmissionFromBlob` - `getRepsFromBlob` - `getFilesFromBlob` - Preserved existing behavior: - same BASE_URL and hash query composition via `hashAPIPath(...)` - same catch-path logging behavior (`consoleLogger`) - no changes to delete/download flows or hash-signing helper usage in mutation paths Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: targeted hygiene in `documentDirectService` to isolate remaining non-migrated special-case flows (`downloadBlob`, delete helpers) and assess if any shared client abstraction is beneficial without altering behavior. --- ### CL-047: TASK22260 next slice — case direct service low-risk getJson adoption date: 2026-03-25 author: Cline scope: `actions/services/caseDirectService.js` type: change rationale: Continue incremental endpoint client rollout with a bounded low-risk set of case service GET helpers that already return direct JSON payloads and have simple logging-only catch paths. impact: Reduces repeated axios GET/response extraction boilerplate and aligns additional case retrieval helpers with shared client conventions. status: completed Summary: - Added `getJson` usage in selected `caseDirectService` helper functions: - `getAppealPDFDocs` - `getPortalModuleDetails` - `getPortalModuleDetailsProxy` - Preserved existing behavior contracts: - same request URL/query construction - same catch-path logging via `consoleLogger` - no change to handlers with bespoke error-return contracts (`getAppealPDFDocument`) or other non-targeted flows. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: migrate additional safe case service GET helpers that currently use `axios.get(...).then(res.data)` to `getJson` where custom catch behavior is compatible. --- ### CL-048: TASK22260 next slice — case direct service GET cluster expansion date: 2026-03-25 author: Cline scope: `actions/services/caseDirectService.js` type: change rationale: Continue phased endpoint client adoption by migrating another bounded set of case service GET helpers that already use shared catch handling (`logAndReturnResponse`). impact: Further reduces duplicated axios GET/response extraction boilerplate while preserving existing error-handling contracts for migrated paths. status: completed Summary: - Migrated additional case retrieval helpers from `axios.get(...).then(res.data)` to `getJson(...)`: - `getCaseMessage` - `getIncidentbyID` - `getIsPublishedbyID` - `getPartSavedAppeal` - `getSIPSEvents` - `getSIPSMedia` - Preserved behavior contracts: - unchanged URLs/query parameter composition - unchanged catch behavior via `logAndReturnResponse` - left non-targeted/bespoke flows untouched (`getAppealID`, create/update/patch operations, and error-response-specialized helpers) Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: evaluate remaining GET helpers in `caseDirectService` with custom catches (`getCase`, `getCaseByID`, `getAppealPDFDocument`) for selective migration where return-shape contracts remain stable. --- ### CL-049: TASK22260 next slice — case direct service remaining GET helper migration date: 2026-03-25 author: Cline scope: `actions/services/caseDirectService.js` type: change rationale: Complete the remaining safe GET-helper client migration in case service by moving custom-catch read functions to `getJson` while preserving their existing return-shape/error handling behavior. impact: Removes remaining direct axios GET response-extraction boilerplate in case read helpers and completes endpointClient read-path consistency for this service subset. status: completed Summary: - Migrated remaining targeted case read helpers from direct `axios.get(...).then(res.data)` to `getJson(...)`: - `getCase` - `getCaseByID` - `getAppealPDFDocument` - Preserved behavior contracts: - unchanged request URL/query construction - unchanged catch semantics: - `getCase` / `getCaseByID` still log via `consoleLogger` - `getAppealPDFDocument` still logs and returns `error.response` on failure - left non-targeted POST/update/create/patch flows unchanged. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: evaluate config-based POST helpers in `caseDirectService` (`createNewCase`, `createNewCaseBlob`, `updateCase`, `updateCaseBlob`) for selective `requestJson(...)` adoption while preserving existing side effects and error contracts. --- ### CL-050: TASK22260 next slice — case direct service POST helper requestJson adoption date: 2026-03-25 author: Cline scope: `actions/services/caseDirectService.js` type: change rationale: Continue bounded client-layer migration by moving config-based case service POST helpers from direct `axios(config)` usage to shared `requestJson(...)` while preserving current behavior and error semantics. impact: Reduces duplicated config-execution/response-extraction boilerplate and aligns case service write-helper internals with existing endpoint client conventions. status: completed Summary: - Migrated selected case service POST helpers to `requestJson(config)`: - `createNewCase` - `createNewCaseBlob` - `updateCase` - `updateCaseBlob` - Preserved behavior contracts: - unchanged payload/query construction and URLs - unchanged catch-path logging via `consoleLogger` - no changes to non-targeted helper logic (`getAppealID`, `patchCase`, and already-migrated GET helpers) Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: assess `patchCase` and `getAppealID` for migration opportunities (if/when preserving their specific behavior contracts remains straightforward). --- ### CL-051: TASK22260 next slice — case direct service final axios dependency removal date: 2026-03-25 author: Cline scope: `actions/services/caseDirectService.js` type: change rationale: Complete the bounded case service migration by replacing the remaining direct axios usage (`getAppealID`, `patchCase`) with shared endpoint client reads, enabling removal of the direct axios import. impact: Finalizes endpoint client consistency in case service and removes remaining direct axios dependency from this module without changing helper contracts. status: completed Summary: - Migrated remaining direct axios-based read helpers to `getJson(...)`: - `getAppealID` - `patchCase` - Preserved behavior contracts: - `getAppealID` still extracts first non-underscore key value from returned entity and logs on failure - `patchCase` still swallows failure (no explicit returned error contract introduced) - Removed now-unused `axios` import from `caseDirectService`. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: review other direct service modules for any remaining legacy `axios` import usage now that case service migration is complete. --- ### CL-052: TASK22260 next slice — portal direct service requestJson parity for config-based reads/deletes date: 2026-03-25 author: Cline scope: `actions/services/portalDirectService.js` type: change rationale: Continue bounded direct-service consistency by migrating remaining config-based portal helper calls from `axios(config)` to shared `requestJson(...)` where no signed-delete/header-specific behavior is required. impact: Reduces repeated config execution/response extraction boilerplate and improves request helper consistency in portal service while preserving behavior. status: completed Summary: - Migrated selected config-based helpers to `requestJson(config)`: - `deleteAwaitingSubmissions` - `sendCaseCompleteMessage` - `sendCaseCompleteMessageProxy` - `sendRepCompleteMessage` - Preserved behavior contracts: - unchanged query/hash composition and request methods - unchanged catch-path logging via `consoleLogger` - left signed delete helpers with bespoke axios/header behavior unchanged (`deleteMyRepresentations`, `deleteWatchedCases`) Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: assess whether signed-delete helpers in `portalDirectService` should remain explicit axios calls (for clarity on headers/hash semantics) or move to a dedicated signed-request client helper. --- ### CL-053: Architecture documentation update — current-state assessment + prioritised roadmap date: 2026-03-25 author: Cline scope: `context/architecture.md` type: change rationale: User requested the architectural assessment be documented in-project so current state, residual risks, and recommended sequencing are explicitly captured for team planning. impact: Improves documentation clarity and planning alignment; no runtime behavior changes. status: completed Summary: - Added a new section to `context/architecture.md`: - **Current State Assessment and Prioritised Next Steps (2026-03-25)** - Documented: - strengths (governance maturity, API/relay hardening progress, façade decomposition progress) - residual risks/gaps (remaining direct-service inconsistency, coverage concentration, logging variance, i18n parity automation gap) - prioritised next steps with rationale - recommended execution sequencing (immediate/next/after) Validation: - Manual coherence check against existing guardrails/runbook/integration-map and memory-bank context. Follow-ups: - Optional: convert the prioritised steps into a sprint-ready plan (tasks, acceptance criteria, validation matrix, rollback notes). --- ### CL-054: Branch correction — include residual duplication/axios risk slices (search + signed-delete portal flows) date: 2026-03-25 author: Cline scope: `actions/services/{portalDirectService,searchDirectService}.js`, `context/architecture.md` type: change rationale: User requested the previously identified primary remaining technical risk slices be explicitly included on this branch, specifically residual axios/duplication in search direct service and signed-delete portal helper flows. impact: Further reduces direct-service axios boilerplate/duplication and aligns additional high-use service paths to shared endpoint client patterns while preserving existing behavior contracts. status: completed Summary: - Implemented the requested risk slices on branch: 1. **Portal signed-delete flow parity** (`portalDirectService`) - migrated signed delete helpers from direct `axios({...}).then(res.data)` to `requestJson({...})`: - `deleteMyRepresentations` - `deleteWatchedCases` - removed now-unused `axios` import from module - preserved hash-signing flow and custom headers semantics 2. **Search direct service axios reduction** (`searchDirectService`) - migrated service GET helpers from direct `axios.get(...).then(res.data)` and `axios(config)` to `getJson(...)` - preserved existing catch semantics (`logAndReturnResponse`, `logAndReturnEmptyValueErrorResponse`, and explicit throw path in `getSearchDocumentDetails`) - removed direct `axios` import from module - Documentation alignment: - retained architecture assessment section in `context/architecture.md` that calls out these residual-risk slices and prioritisation. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: assess whether a dedicated signed-request client helper should encapsulate hash + headers + method conventions to prevent future drift in remaining signed flows. --- ### CL-055: TASK22260 next slice — document direct service signed/delete axios reduction date: 2026-03-25 author: Cline scope: `actions/services/documentDirectService.js` type: change rationale: Execute next bounded risk-reduction slice by migrating remaining non-download document-service delete and signed-get helper calls away from direct axios response extraction to shared endpoint clients. impact: Further reduces duplicated axios boilerplate and aligns document service internals with shared request-client conventions while preserving existing hash/query and catch-path behavior. status: completed Summary: - Migrated signed hashed delete-helper flows from direct `axios({...}).then(res.data)` to `requestJson({...})`: - `deleteAwaitingSubmissionsFromBlob` - `deleteMyRepresentationsFromBlob` - Migrated delete helper GET calls from `axios.get(...).then(res.data)` to `getJson(...)`: - `deleteBlob` - `deleteRepBlob` - Preserved behavior contracts: - unchanged query/hash composition and endpoint URLs - unchanged catch-path logging with `consoleLogger` - Left `downloadBlob` unchanged in this slice (special-case behavior path retained for separate focused handling). Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: isolate and correct `downloadBlob` behavior in `documentDirectService` (including legacy `res` usage) behind an explicit, tested contract. --- ### CL-056: TASK22260 next slice — document direct service download helper contract fix date: 2026-03-25 author: Cline scope: `actions/services/documentDirectService.js` type: change rationale: Execute the next bounded follow-up by correcting the legacy `downloadBlob` service helper path that still relied on invalid `res` references and direct axios usage, aligning it to shared request client behavior. impact: Fixes a service-layer contract defect risk in document download helper and improves consistency by using shared request client patterns; no endpoint contract change. status: completed Summary: - Refactored `downloadBlob(containerName, blobName)` in `documentDirectService`: - removed legacy direct `axios.get(...).then(response => res.status(...))` pattern that referenced undefined `res` in service layer - now returns blob response data via `requestJson({ method: "get", url, responseType: "blob" })` - preserved catch-path logging (`consoleLogger`) - Removed now-unused module-level `axios` import from `documentDirectService`. Validation: - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: add a focused test (or integration harness assertion) around `downloadBlob` service return contract to prevent regression to response-object assumptions. --- ### CL-057: TASK22260 next slice — phase7 behavioural harness compatibility update date: 2026-03-25 author: Cline scope: `tests/phase7/service-behaviour.test.cjs` type: change rationale: After service-layer client migration (`getJson`/`requestJson`/`buildHashedQueryUrl`), phase7 behavioural harness still assumed direct axios imports only; update harness defaults so legacy behavior assertions remain executable. impact: Restores service behavioural regression coverage (12/12) without changing production runtime code. status: completed Summary: - Enhanced phase7 VM loader default injections for migrated service helpers: - added default `getJson(...)` mock delegating to `axios.get(...).then(res.data)` - added default `requestJson(...)` mock delegating to `axios(config).then(res.data)` - added default `buildHashedQueryUrl(...)` mock resolving hash via `/api/endpoint/gethash_api` compatibility path - Updated notify behavior assertions to align with shared request client usage (`requestJson` invokes axios config-style call): - switched notify test handlers from `axios.postHandler` to `axios.requestHandler` - assertions now inspect `axios.calls[0].config.{url,method,data}` Validation: - `node tests/phase7/service-behaviour.test.cjs` -> pass (12/12) Follow-ups: - Optional next bounded slice: add a small shared test utility for service harness client mocks to reduce future per-file drift as façade migration continues. --- ### CL-058: TASK22260 next slice — phase6 behavioural harness compatibility parity date: 2026-03-25 author: Cline scope: `tests/phase6/service-behaviour.test.cjs` type: change rationale: Keep older phase6 behavioural harness aligned with service client-wrapper migration by adding default helper injections required by `getJson`/`requestJson`-based direct services. impact: Restores phase6 behavioural regression execution parity (8/8) with no runtime code changes. status: completed Summary: - Updated `loadServiceModule` default context in `tests/phase6/service-behaviour.test.cjs`: - added default `getJson(...)` mock backed by `axios.get(...).then(res.data)` - added default `requestJson(...)` mock backed by `axios(config).then(res.data)` - Preserved existing test assertions and behavior semantics; this is harness-compatibility only. Validation: - `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) Follow-ups: - Optional consolidation: extract shared phase6/phase7 VM loader helpers into a single test utility to reduce duplication. --- ### CL-059: TASK22260 next slice — shared service harness extraction (continued bounded risk-reduction) date: 2026-03-25 author: Cline scope: `tests/{serviceHarness,phase6/service-behaviour,phase7/service-behaviour}.cjs` type: change rationale: Continue the bounded risk-reduction stream by removing duplicated test harness infrastructure across phase6/phase7 service behavioural suites and centralizing client-wrapper-compatible mocks. impact: Reduces test harness drift risk and keeps client-wrapper migration verification stable across multiple suites, without runtime code changes. status: completed Summary: - Added shared helper module `tests/serviceHarness.cjs` with reusable: - `createAxiosMock` - `createLoggerMock` - `createAxiosError` - `loadServiceModule` (with default `getJson`/`requestJson`/`buildHashedQueryUrl` injections) - `normalize` - Refactored `tests/phase6/service-behaviour.test.cjs` to import shared harness utilities and remove duplicated local harness implementation. - Refactored `tests/phase7/service-behaviour.test.cjs` to import shared harness utilities and remove duplicated local harness implementation. Validation: - `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8) - `node tests/phase7/service-behaviour.test.cjs` -> pass (12/12) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded risk-reduction slice: evaluate whether other legacy service test suites can adopt `tests/serviceHarness.cjs` to standardize migration-era service mocking behavior. --- ### CL-060: TASK22260 next slice — core token helper client-wrapper migration (continued bounded risk-reduction) date: 2026-03-25 author: Cline scope: `actions/core/token.js` type: change rationale: Include the identified remaining candidate outside `actions/services` and continue the bounded risk-reduction stream by removing direct axios response extraction from core token retrieval. impact: Aligns token helper request execution with shared endpoint client conventions while preserving existing token caching and error-return behavior. status: completed Summary: - Refactored `getToken` in `actions/core/token.js`: - replaced direct `axios.post(...).then(res => res.data)` chain with shared `requestJson({...})` - migrated function to `async/await` with equivalent `try/catch` behavior - retained existing semantics: - successful token payload cached in `cache.tokenResponse` - failures logged via `consoleLogger` and returned to caller - Removed direct `axios` dependency from `actions/core/token.js` in favor of `actions/clients/endpointClient`. Validation: - `node tests/phase21/api-contract-slice1.test.cjs` -> pass - helper: 4/4 - file-handler: 53/53 - email-handler: 12/12 - endpoint-handler: 164/164 - documents-handler: 3/3 - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded risk-reduction slice: assess whether any remaining non-service utility modules still use promise-chain axios extraction patterns and migrate them to shared clients where behavior contracts remain unchanged. --- ### CL-061: TASK22260 next slice — core token regression coverage addition (bounded hardening) date: 2026-03-25 author: Cline scope: `tests/phase22/core-token-behaviour.test.cjs` type: change rationale: Follow the previous core token migration with a bounded verification slice to lock the request-client contract and prevent regression to direct axios extraction patterns. impact: Improves confidence in `actions/core/token.js` behavior (success + failure semantics) without runtime code changes. status: completed Summary: - Added new focused Phase 22 behavioural test suite: - `tests/phase22/core-token-behaviour.test.cjs` - Coverage asserts: - `getToken` success path returns token payload and calls `requestJson` with expected URL/method/body/headers - failure path logs via `consoleLogger` and returns the original error object - Test harness uses VM import stripping consistent with existing phase behavioural suites. Validation: - `node tests/phase22/core-token-behaviour.test.cjs` -> pass (2/2) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: add this phase22 suite to any aggregate test runner used in CI if/when phase-level suites are centrally orchestrated. --- ### CL-062: TASK22260 next slice — phase22 runner export guard parity (bounded test-harness consistency) date: 2026-03-25 author: Cline scope: `tests/phase22/core-token-behaviour.test.cjs` type: change rationale: Continue bounded test-hardening by aligning phase22 test entry behavior with established suite conventions so it can be executed both directly and from aggregate runners. impact: Improves test harness composability and reduces accidental double-execution risk when importing phase22 test suites. status: completed Summary: - Updated `tests/phase22/core-token-behaviour.test.cjs` to export `run` and add `require.main === module` guard. - Preserved direct CLI execution behavior while enabling safe module import by aggregate runners. Validation: - `node tests/phase22/core-token-behaviour.test.cjs` -> pass (2/2) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: add a dedicated `tests/phase22/index.test.cjs` aggregate entrypoint if additional phase22 suites are introduced. --- ### CL-063: TASK22260 next slice — phase22 aggregate runner entrypoint (bounded test-runner hardening) date: 2026-03-25 author: Cline scope: `tests/phase22/index.test.cjs` type: change rationale: Continue the bounded test-harness stream by introducing a phase-level aggregate runner for phase22, matching established conventions used in other phase suites. impact: Improves consistency and future scalability of phase22 tests by enabling a single entry command as additional phase22 suites are added. status: completed Summary: - Added `tests/phase22/index.test.cjs` aggregate runner. - Runner currently executes `core-token-behaviour.test.cjs` and prints a phase-level completion line. - Exported `run` and kept direct CLI execution guard parity (`require.main === module`). Validation: - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - phase22 combined: pass - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: add additional phase22 suites (e.g., shared-client utility behaviour tests) under this aggregate runner as migration coverage expands. --- ### CL-064: TASK22260 next slice — phase22 client utility behaviour coverage expansion date: 2026-03-25 author: Cline scope: `tests/phase22/{client-utils-behaviour,index}.test.cjs` type: change rationale: Execute the next bounded phase22 slice by adding focused behavioural coverage for shared client utilities to reduce regression risk as direct-service/client-wrapper migration continues. impact: Improves confidence in shared client helper contracts (`endpointClient`, `relayClient`) and keeps phase22 aggregate suite aligned with new coverage. status: completed Summary: - Added new suite: `tests/phase22/client-utils-behaviour.test.cjs`. - Added assertions for shared client utility behavior: - `endpointClient.getJson` returns `axios.get(...).data` - `endpointClient.requestJson` returns `axios(config).data` - `relayClient.buildHashedQueryUrl` appends browser hash-service response - server fallback path uses `hashAPIPath` when `HASHKEY` is present - browser/no-HASHKEY failure path rethrows hash-service error - Updated `tests/phase22/index.test.cjs` to include the new client-utils suite in the phase aggregate runner. Validation: - `node tests/phase22/client-utils-behaviour.test.cjs` -> pass (5/5) - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 5/5 - phase22 combined: pass - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: add focused phase22 behavioural coverage for any future shared client wrappers introduced beyond `endpointClient`/`relayClient`. --- ### CL-065: TASK22260 next slice — fileClient extraction + phase22 behavioural coverage date: 2026-03-25 author: Cline scope: `actions/clients/{fileClient,index}.js`, `actions/services/documentDirectService.js`, `tests/phase22/{file-client-behaviour,index}.test.cjs` type: change rationale: Continue bounded shared-client decomposition by extracting repeated file-route request patterns into `fileClient` and hardening behaviour with dedicated phase22 tests. impact: Reduces request-boilerplate duplication in document service and increases regression confidence for extracted file client helper contracts. status: completed Summary: - Added new shared client wrapper: `actions/clients/fileClient.js`: - `getFileJson(url)` - `getSignedFileJson(queryUrl)` - `downloadFileBlob(url)` - Exported `fileClient` from `actions/clients/index.js` (and therefore via `actions/index.js` barrel path). - Migrated a bounded subset of `actions/services/documentDirectService.js` call sites to `fileClient` while preserving catch-path logging behavior: - `getFilesFromBlobproxy` -> `getFileJson` - `deleteAwaitingSubmissionsFromBlob` -> `getSignedFileJson` - `deleteMyRepresentationsFromBlob` -> `getSignedFileJson` - `deleteBlob` -> `getFileJson` - `deleteRepBlob` -> `getFileJson` - `downloadBlob` -> `downloadFileBlob` - Added `tests/phase22/file-client-behaviour.test.cjs` covering: - delegation to `getJson` - signed URL generation + `requestJson` invocation - blob download config contract (`responseType: "blob"`) - Updated aggregate runner `tests/phase22/index.test.cjs` to include file-client suite. Validation: - `node tests/phase22/file-client-behaviour.test.cjs` -> pass (3/3) - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 5/5 - file-client: 3/3 - phase22 combined: pass - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: evaluate whether additional `documentDirectService` file-route call sites can adopt `fileClient` without altering current behavior contracts. --- ### CL-066: TASK22260 next slice — service harness parity for fileClient helper injections date: 2026-03-25 author: Cline scope: `tests/serviceHarness.cjs` type: change rationale: Follow the previous `fileClient` extraction with a bounded harness-compatibility slice so legacy VM-based service behavioural suites continue to execute without requiring per-test manual injections. impact: Restores migration-era behavioural regression stability (phase7) by aligning shared harness defaults with newly introduced file client helper symbols. status: completed Summary: - Updated shared test harness defaults in `tests/serviceHarness.cjs` to inject file-client compatible helpers when not explicitly provided: - `getFileJson` (delegates to default `getJson`) - `getSignedFileJson` (signs via `buildHashedQueryUrl` then calls `requestJson` with GET config) - `downloadFileBlob` (calls `requestJson` with GET + `responseType: "blob"`) - This preserves existing VM import-stripping strategy while preventing `ReferenceError` in migrated services that import from `../clients/fileClient`. Validation: - `node tests/phase7/service-behaviour.test.cjs` -> pass (12/12) - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 5/5 - file-client: 3/3 - phase22 combined: pass - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: add a focused phase6/phase7 behavioural assertion for `documentDirectService.downloadBlob` to explicitly lock the `downloadFileBlob` delegation contract. --- ### CL-067: TASK22260 next slice — phase7 downloadBlob delegation behavioural lock date: 2026-03-25 author: Cline scope: `tests/phase7/service-behaviour.test.cjs` type: change rationale: Execute the queued follow-up by adding explicit phase7 behavioural coverage for `documentDirectService.downloadBlob` so file-client delegation and blob request config remain contract-stable. impact: Increases regression confidence for document download helper behaviour after `fileClient` extraction, without runtime code changes. status: completed Summary: - Added new phase7 behavioural test: - `document/downloadBlob delegates blob request config via file client helper` - The test asserts: - `downloadBlob` lower-cases container in URL composition - request is issued through config-style request path (`axios.request` in harness) - request method is `get` - `responseType` is `blob` - returned payload contract is preserved from request helper data. Validation: - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 5/5 - file-client: 3/3 - phase22 combined: pass - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next bounded slice: evaluate adding equivalent focused behavioural coverage in phase6 if download helper behavior becomes part of that 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.js` with: - `postSignedFileJson(queryUrl, data, config = {})` - signs query URL via `buildHashedQueryUrl` and executes POST via `requestJson` - Migrated all remaining signed POST helper paths in `actions/services/documentDirectService.js` to `postSignedFileJson`: - `uploadFiles` - `uploadSingleFile` - `uploadRepFiles` - `generateRepPDF` - `generateAppealPDF` - Preserved existing catch-path logging and request-option semantics: - multipart headers for upload flows - conditional `responseType: "blob"` for download variants - Expanded phase22 file-client behavior suite with explicit POST-signed contract test: - URL signing + POST method - data passthrough - config/header passthrough Validation: - `node tests/phase22/file-client-behaviour.test.cjs` -> pass (4/4) - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 5/5 - file-client: 4/4 - phase22 combined: pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next widened slice: evaluate consolidating remaining direct `getJson` file-read flows in `documentDirectService` behind `fileClient` for full per-module client symmetry. --- ### CL-069: TASK22260 widened module-completion slice — documentDirectService file-read client symmetry date: 2026-03-25 author: Cline scope: `actions/services/documentDirectService.js` type: change rationale: Continue widened slice cadence by completing per-module client symmetry in `documentDirectService`, moving all file-read helper calls to `fileClient` instead of mixed endpoint client usage. impact: Simplifies module dependency shape and centralizes file-route read behavior through a single client abstraction without changing runtime contracts. status: completed Summary: - Removed mixed `endpointClient` usage from `documentDirectService` for file reads. - Migrated remaining file-read/helper routes from `getJson` to `getFileJson`: - `getAwaitingSubmissionFromBlob` - `getRepsFromBlob` - `getRepsFromBlobProxy` - `getAwaitingSubmissionFromBlobProxy` - `getFilesFromBlob` - `getFilesFromBlobHashed` - `getProgressFromBlob` - `createContainerProxy` - Removed now-unused imports from `documentDirectService`: - `buildHashedQueryUrl` - `getJson` - `requestJson` Validation: - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 5/5 - file-client: 4/4 - phase22 combined: pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next widened slice: introduce a small `fileClient` URL-builder helper set for repeated query-string composition in `documentDirectService` (container/casefolder/blob parameters) to reduce string-concat drift risk. --- ### CL-070: TASK22260 widened cross-file slice — file route builder extraction + document service query normalization date: 2026-03-25 author: Cline scope: `actions/clients/{fileRouteBuilder,index}.js`, `actions/services/documentDirectService.js`, `tests/{serviceHarness,phase22/client-utils-behaviour}.cjs` type: change rationale: Deliver a wider-than-previous slice by extracting reusable file-route query composition helpers and applying them across document service paths, reducing repeated string concatenation and encoding drift risk. impact: Improves maintainability and consistency of file-route URL construction while preserving existing runtime contracts and hash behavior. status: completed Summary: - Added new shared helper module: - `actions/clients/fileRouteBuilder.js` - exports: - `buildFileQuery(path, params, options)` (supports optional encoded query composition) - `withBaseUrl(baseUrl, route)` - `appendQuerySuffix(route, suffix)` - Exported route-builder helpers via `actions/clients/index.js`. - Refactored `actions/services/documentDirectService.js` to use route-builder helpers across read/delete/download/query flows: - normalized composition for file routes and hash suffix append behavior - preserved encoded-path behavior for sensitive params (`casefolderID`, `blobname`) where previously encoded - preserved base URL prefix behavior and existing logger/catch semantics - Updated test harness defaults in `tests/serviceHarness.cjs` for new helper symbols: - `buildFileQuery` - `withBaseUrl` - `appendQuerySuffix` - Expanded phase22 utility coverage in `tests/phase22/client-utils-behaviour.test.cjs` with file route-builder behavior assertions. Validation: - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 6/6 - file-client: 4/4 - phase22 combined: pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next widened slice: evaluate applying `fileRouteBuilder` to portal/case service file-route call sites for cross-module query-builder consistency. --- ### CL-071: TASK22260 next widened cross-module slice — portal service query normalization via fileRouteBuilder date: 2026-03-25 author: Cline scope: `actions/services/portalDirectService.js` type: change rationale: Deliver the requested next wider slice by extending `fileRouteBuilder` adoption beyond document service into portal service, reducing duplicated query string concatenation and improving consistency in signed/unsigned route construction. impact: Improves maintainability and query-construction consistency across high-use portal service flows while preserving existing runtime behavior and hash-signing contracts. status: completed Summary: - Refactored `actions/services/portalDirectService.js` to use shared route helpers: - `buildFileQuery` - `withBaseUrl` - `appendQuerySuffix` - Normalized query composition across portal service GET/DELETE/message flows: - read/list endpoints (`getMyCases`, `getMyInvolvements`, `getMyLPACases`, `getMyRepresentations`, proxy and watched/awaiting variants) - delete endpoints (`deleteMyRepresentations`, `deleteAwaitingSubmissions`, `deleteWatchedCases`) - file-message endpoints (`sendCaseCompleteMessage`, `sendCaseCompleteMessageProxy`, `sendRepCompleteMessage`) - Preserved behavior contracts: - retained BASE_URL usage patterns for existing BASE_URL-prefixed routes - retained hash-signing flow via `buildHashedQueryUrl` - retained append semantics for signed suffixes in `sendCaseCompleteMessage` - retained request methods, headers, payloads, and catch-path logging Validation: - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 6/6 - file-client: 4/4 - phase22 combined: pass - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next widened slice: apply the same query-normalization helpers in `caseDirectService` and add dedicated phase22 behavioral assertions for `portalDirectService` route-building/signing composition. --- ### CL-072: TASK22260 next widened cross-module slice — case service query normalization via fileRouteBuilder date: 2026-03-25 author: Cline scope: `actions/services/caseDirectService.js`, `tests/phase6/service-behaviour.test.cjs` type: change rationale: Continue widened cross-module rollout by applying shared query/route composition helpers to `caseDirectService`, reducing repeated string concatenation and aligning route construction style with document/portal services. impact: Improves maintainability and consistency in case service URL/query composition while preserving existing runtime behavior and error contracts. status: completed Summary: - Refactored `actions/services/caseDirectService.js` to use `fileRouteBuilder` helpers: - `buildFileQuery` - `withBaseUrl` - Normalized route composition for read and write helpers, including: - case retrieval/search flows (`getCaseMessage`, `getIncidentbyID`, `getIsPublishedbyID`, `getPartSavedAppeal`, `getSIPSEvents`, `getSIPSMedia`) - appeal resolution/update/create flows (`getAppealID`, `createNewCase`, `createNewCaseBlob`, `updateCase`, `updateCaseBlob`, `patchCase`) - case/detail/document/module reads (`getCase`, `getCaseByID`, `getAppealPDFDocs`, `getAppealPDFDocument`, `getPortalModuleDetails`, `getPortalModuleDetailsProxy`) - Preserved existing contracts: - BASE_URL usage patterns where previously applied - method/payload semantics for `requestJson` paths - catch-path logging and return behavior (`logAndReturnResponse`, `consoleLogger`, `error.response` paths) - Expanded phase6 behavioural coverage with a focused assertion for case route composition: - `case/getPortalModuleDetails composes BASE_URL route with encoded case reference` Validation: - `node tests/phase6/service-behaviour.test.cjs` -> pass (9/9) - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 6/6 - file-client: 4/4 - phase22 combined: pass - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional next widened slice: add a focused phase22 behavioral suite for `caseDirectService` and normalize any remaining specialized encoding usage behind explicit helper options where appropriate. --- ### CL-073: TASK22260 essential condensed slice — case phase22 behavioural coverage + encoding contract lock date: 2026-03-25 author: Cline scope: `tests/phase22/{case-service-behaviour,index}.test.cjs` type: change rationale: Condense remaining core work into one essential slice by adding explicit phase22 behavioural coverage for `caseDirectService` route composition and encoding-sensitive contracts. impact: Improves regression confidence for case service route-building behavior (BASE_URL composition, case-reference encoding/escaping, error-return contracts) without runtime behavior changes. status: completed Summary: - Added new suite `tests/phase22/case-service-behaviour.test.cjs` with focused behavioural assertions for: - `getPortalModuleDetails` BASE_URL + encoded case reference composition - `getPortalModuleDetailsProxy` apostrophe escape behavior in case reference - `getAppealID` query composition and non-underscore value extraction - `getAppealPDFDocument` failure-path logging + `error.response` passthrough - Updated `tests/phase22/index.test.cjs` aggregate runner to include `case-service-behaviour` suite. Validation: - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 6/6 - file-client: 4/4 - case-service: 4/4 - phase22 combined: pass - `node tests/phase6/service-behaviour.test.cjs` -> pass (9/9) - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Optional closure slice: add a dedicated phase22 portal-service behavioural suite and finish harmonization of remaining direct query string composition in `portalDirectService` write helpers. --- ### CL-074: TASK22260 optional closure condensed slice — portal phase22 behavioural coverage + final write-helper query harmonization date: 2026-03-25 author: Cline scope: `actions/services/portalDirectService.js`, `tests/phase22/{portal-service-behaviour,index}.test.cjs` type: change rationale: Complete optional closure work as one condensed slice by adding explicit portal behavioral coverage and removing remaining direct literal query strings in portal write helpers. impact: Improves regression confidence for signed portal flows and closes remaining route-composition harmonization gap in portal service write helpers without changing runtime behavior contracts. status: completed Summary: - Harmonized remaining portal write-helper route literals to `buildFileQuery(...)`: - `createWatchedCases` - `setRepInvolvment` - `setCaseInvolvment` - Added new phase22 suite `tests/phase22/portal-service-behaviour.test.cjs` covering: - signed hash suffix append path in `sendCaseCompleteMessage` - signed delete request contract + headers in `deleteMyRepresentations` - harmonized route helper URL in `createWatchedCases` - signed pre-request rejection contract in `sendRepCompleteMessage` when hash-signing fails - Updated `tests/phase22/index.test.cjs` aggregate runner to include `portal-service-behaviour`. Validation: - `node tests/phase22/portal-service-behaviour.test.cjs` -> pass (4/4) - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 6/6 - file-client: 4/4 - case-service: 4/4 - portal-service: 4/4 - phase22 combined: pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Closure for this condensed stream complete; any further work should be a separate expansion stream (e.g., additional service-level phase22 coverage breadth). --- ### CL-075: TASK22260 sequence-A step3 completion slice — auth redirect safety + EN/CY route parity automation date: 2026-03-25 author: Cline scope: `tests/phase22/{auth-redirect-safety,i18n-route-parity,index}.test.cjs` type: change rationale: Continue on this branch to complete the remaining sequence-A step3 gaps by adding explicit automated checks for auth callback/redirect safety and EN/CY route parity. impact: Improves confidence in auth redirect safety behavior and bilingual rewrite parity with targeted, low-risk regression checks and no runtime code changes. status: completed Summary: - Added `tests/phase22/auth-redirect-safety.test.cjs`: - validates locale resolution precedence (`query -> body -> cookie -> default en`) - validates redirect callback behavior for: - relative URL to same base - same-origin absolute URL passthrough - external URL rewritten to locale-safe base origin with preserved path/query - Added `tests/phase22/i18n-route-parity.test.cjs`: - asserts presence of required CY rewrite aliases for auth/policy routes in `next.config.js` - includes checks for signin/email/error/verify-request + privacy/accessibility/terms routes - Updated `tests/phase22/index.test.cjs` to include both new suites in aggregate phase22 execution. Validation: - `node tests/phase22/auth-redirect-safety.test.cjs` -> pass (4/4) - `node tests/phase22/i18n-route-parity.test.cjs` -> pass (1/1) - `node tests/phase22/index.test.cjs` -> pass - core-token: 2/2 - client-utils: 6/6 - file-client: 4/4 - case-service: 4/4 - portal-service: 4/4 - auth-redirect: 4/4 - i18n-route: 1/1 - phase22 combined: pass - `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) Follow-ups: - Sequence A step3 targeted gaps are now covered; further test expansion should be treated as new scope (e.g., deeper end-to-end journey assertions). --- ### CL-076: TASK22269 Slice B1.1 — signed-request helper set + portal pilot signed-flow migration date: 2026-03-25 author: Cline scope: `actions/clients/{signedRequestClient,index}.js`, `actions/services/portalDirectService.js`, `tests/{serviceHarness,phase22/portal-service-behaviour}.cjs` type: change rationale: Execute Sequence B Workstream B1 pilot by introducing shared signed request helpers (GET/POST/DELETE) and migrating one bounded portal signed flow without broader module rollout. impact: Reduces duplication and drift risk in hash-signing + method execution paths while preserving existing signed-flow behavior contracts. status: completed Summary: - Added new shared signed-request client helper module: - `actions/clients/signedRequestClient.js` - exports: - `getSignedJson(queryUrl, config?)` - `postSignedJson(queryUrl, data, config?)` - `deleteSignedJson(queryUrl, config?)` - all helpers use existing `buildHashedQueryUrl(...)` + `requestJson(...)` composition to preserve signing semantics - Exported new helper module via `actions/clients/index.js`. - Migrated exactly one pilot signed flow in portal service: - `deleteWatchedCases` in `actions/services/portalDirectService.js` - from inline `buildHashedQueryUrl(...).then(requestJson(...))` to `deleteSignedJson(queryUrl)` - preserved existing catch/log behavior (`consoleLogger` + `undefined` return on catch) - Added test harness compatibility for VM import-stripping suites: - `tests/serviceHarness.cjs` now injects default `deleteSignedJson` mock behavior. - Expanded portal behavioral tests with explicit negative-path assertion: - `tests/phase22/portal-service-behaviour.test.cjs` - verifies `deleteWatchedCases` logs and safely returns `undefined` when signed delete fails. Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - portal-service suite now 5/5 including signed-delete failure path - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Continue Sequence B B1 in future bounded slices by migrating additional signed flows one module/function cluster at a time (outside this slice). --- ### CL-077: TASK22269 Slice B1.2 — portal signed-delete bundle (headered delete migration) date: 2026-03-25 author: Cline scope: `actions/services/portalDirectService.js` type: change rationale: Continue signed-request consolidation using bounded grouping by migrating the remaining portal signed delete flow (`deleteMyRepresentations`) onto shared signed helper while preserving required OData headers. impact: Further reduces duplicated sign+delete boilerplate in portal service and centralizes signed DELETE execution semantics. status: completed Summary: - Migrated `deleteMyRepresentations` from inline `buildHashedQueryUrl(...).then(requestJson(...))` to shared `deleteSignedJson(queryUrl, { headers })`. - Preserved behavior-critical headers exactly: - `OData-MaxVersion` - `OData-Version` - `Accept` - `Prefer` - `Content-Type` - Preserved existing catch/log behavior (`consoleLogger` with safe undefined return on failure). Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Next bounded signed GET candidate in portal service is `sendRepCompleteMessage` (single signed URL + GET request path). --- ### CL-078: TASK22269 Slice B1.3 — fileClient signed helper delegation bundle date: 2026-03-25 author: Cline scope: `actions/clients/fileClient.js`, `tests/phase22/file-client-behaviour.test.cjs` type: change rationale: Continue grouped signed-request consolidation by reducing duplicate signing logic in `fileClient` and delegating signed GET/POST operations to shared `signedRequestClient` helpers. impact: Centralizes signed method execution behavior in one helper layer and lowers drift risk across file-service call paths. status: completed Summary: - Updated `actions/clients/fileClient.js`: - replaced direct `buildHashedQueryUrl + requestJson` logic in: - `getSignedFileJson` -> now delegates to `getSignedJson` - `postSignedFileJson` -> now delegates to `postSignedJson` - retained `downloadFileBlob` and `getFileJson` behavior unchanged. - Updated `tests/phase22/file-client-behaviour.test.cjs` to assert delegation contracts for `getSignedJson` and `postSignedJson` rather than direct signing internals. Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Candidate map now indicates remaining explicit signed request composition is primarily in account/portal signed GET edge paths (`getPortalLogin`, `sendRepCompleteMessage`, and signed suffix append flow in `sendCaseCompleteMessage`) for future bounded slices. --- ### CL-079: TASK22269 Slice B1.4 — signed GET consolidation bundle (portal + account) date: 2026-03-25 author: Cline scope: `actions/clients/signedRequestClient.js`, `actions/services/{portalDirectService,accountDirectService}.js`, `tests/{serviceHarness,phase22/portal-service-behaviour,phase7/service-behaviour}.cjs` type: change rationale: Continue grouped signed-request migration by consolidating remaining direct signed-GET composition paths onto shared signed helper primitives while preserving route behavior contracts. impact: Reduces residual signing duplication and standardizes signed URL creation across portal/account service read/message flows. status: completed Summary: - Enhanced `signedRequestClient`: - added `buildSignedUrl(queryUrl, { baseUrl? })` helper for signed URL generation reuse - updated internal signed request execution to use `buildSignedUrl` - Migrated account signed GET candidate: - `accountDirectService.getPortalLogin` now uses `getSignedJson(queryUrl, { baseUrl: BASE_URL })` - preserved existing error semantics (`consoleLogger` + `JSON.stringify(error)`) - Migrated portal signed GET candidates: - `portalDirectService.sendRepCompleteMessage` now uses `buildSignedUrl(hashQueryPath)` - `portalDirectService.sendCaseCompleteMessage` now uses `buildSignedUrl(hashQueryPath)` + existing signed suffix append behavior - preserved existing request method/URL shape and catch-path behavior - Updated test harness and suites: - `tests/serviceHarness.cjs` now provides defaults for `buildSignedUrl`, `getSignedJson`, `postSignedJson` - `tests/phase22/portal-service-behaviour.test.cjs` includes assertion for `sendRepCompleteMessage` signed-helper delegation - `tests/phase7/service-behaviour.test.cjs` account portal-login expectations aligned to request-config path used by shared signed helper Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Remaining special-case signed pattern is now primarily the signed-suffix append composition in `sendCaseCompleteMessage` (already using shared `buildSignedUrl`), with broader module migrations to be planned in future bounded slices. --- ### CL-080: TASK22269 Slice B1.5 — document hash-suffix route normalization helper date: 2026-03-25 author: Cline scope: `actions/clients/fileRouteBuilder.js`, `actions/services/documentDirectService.js`, `tests/{serviceHarness,phase22/client-utils-behaviour}.cjs` type: change rationale: Continue grouped follow-on candidates by normalizing repeated deterministic hash-suffix route assembly in document service behind one shared route-builder helper. impact: Reduces repeated `appendQuerySuffix(route, hashAPIPath(route))` composition drift risk while preserving route/query/hash behavior. status: completed Summary: - Added `appendHashSuffix(route, hashBuilder)` to `fileRouteBuilder`. - Migrated document service deterministic hash-suffix paths to new helper: - `getAwaitingSubmissionFromBlob` - `getRepsFromBlob` - `getFilesFromBlob` - `getProgressFromBlob` - `createContainerProxy` - Updated shared VM harness defaults (`tests/serviceHarness.cjs`) to inject `appendHashSuffix`. - Expanded phase22 utility test to cover new helper behavior (`tests/phase22/client-utils-behaviour.test.cjs`). Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Remaining non-service candidate for this stream is `actions/azurestorage.js` direct `hashAPIPath` metadata assembly (separate bounded slice if desired). --- ### CL-081: TASK22269 Slice B1.6 — azurestorage hash-query metadata builder normalization date: 2026-03-25 author: Cline scope: `actions/azurestorage.js` type: change rationale: Continue requested follow-on slice by reducing repeated hash-query path string composition in azure storage metadata builders behind local helper functions. impact: Lowers duplication/drift risk in hashed metadata path generation while preserving existing route and encoding behavior. status: completed Summary: - Added internal helper builders in `actions/azurestorage.js`: - `buildDownloadBlobQueryPath(...)` - `buildDeleteBlobQueryPath(...)` - `buildGetBlobListQueryPath(...)` - Replaced repeated inline hash path literals with helper usage in targeted metadata object builders: - `getBlobs` - `getProgressBlobs` - `getRepsFilesBlobs` - Preserved existing behavior semantics for hash path construction: - encoded `casefolderID`/`blobname` where previously encoded - unchanged `containerName` and `casefolderID` value sourcing - unchanged returned object field names and shape Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Remaining potential cleanups in `actions/azurestorage.js` are broader non-slice refactors (legacy logging verbosity, large function decomposition) and should be handled separately to keep risk bounded. --- ### CL-082: TASK22269 Slice B1.7 — azurestorage hash metadata helper consolidation date: 2026-03-25 author: Cline scope: `actions/azurestorage.js` type: change rationale: Continue bounded normalization by consolidating repeated hash metadata object field population into a single local helper. impact: Reduces duplicated metadata field assembly and drift risk while preserving existing output shape and hash behavior. status: completed Summary: - Added `buildHashMetadataPaths({ containerName, casefolderID, blobname })` helper. - Replaced repeated per-object hash metadata assignment in: - `getBlobs` - `getProgressBlobs` - `getRepsFilesBlobs` - Preserved existing metadata contracts: - keys unchanged: `hashedfilepath`, `hasheddeletepath`, `hashgetblobs` - same encoded query path inputs and route semantics. Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Any further `azurestorage.js` cleanup should remain bounded (e.g., logging-only normalization) and separated from behavior-affecting refactors. --- ### CL-083: TASK22269 Slice B1.8 — phase22 azurestorage helper contract coverage date: 2026-03-26 author: Cline scope: `tests/phase22/{azurestorage-helper-behaviour,index}.test.cjs` type: change rationale: Execute the selected bounded test-only follow-up by adding focused regression coverage for recently added azurestorage helper contracts. impact: Improves confidence in query-path and hash-metadata helper output stability without changing runtime behavior. status: completed Summary: - Added new phase22 suite: `tests/phase22/azurestorage-helper-behaviour.test.cjs`. - Test suite isolates helper block from `actions/azurestorage.js` and verifies: - `buildDownloadBlobQueryPath` default encoding output - `buildDeleteBlobQueryPath` non-encoded option behavior - `buildGetBlobListQueryPath` query output contract - `buildHashMetadataPaths` key/value shape (`hashedfilepath`, `hasheddeletepath`, `hashgetblobs`) - Wired suite into aggregate runner `tests/phase22/index.test.cjs`. Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass (includes new azurestorage-helper 4/4) - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Optional next bounded slice: add an explicit assertion for encoded `casefolderID` variants containing reserved query characters (`?`, `&`) if those inputs are expected in future flows. --- ### CL-084: TASK22269 Slice B1.9 — azurestorage local split-value tidy in touched helper consumers date: 2026-03-26 author: Cline scope: `actions/azurestorage.js` type: change rationale: Execute the selected next bounded readability-only slice by reducing repeated `blob.name.split("/")` access in the recently touched helper-consumer functions. impact: Non-behavioral maintainability improvement in azurestorage helper-consumer paths; no API/route contract changes. status: completed Summary: - In targeted functions (`getBlobs`, `getProgressBlobs`, `getRepsFilesBlobs`), introduced local path-part variables to avoid repeated inline splitting: - `blobPathParts` - `fileName` / `appealBlobName` / `repFileName` - `casefolderPath` - Replaced repeated field reads and helper arguments with these locals in object construction and hash metadata composition. - Preserved existing query composition and output shape/keys (including hashed path metadata fields). Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Optional next bounded slice: logging-only normalization in these same azurestorage functions (no behavior change), done separately from structural refactors. --- ### CL-085: TASK22269 Slice B1.10 — azurestorage touched-function logging normalization date: 2026-03-26 author: Cline scope: `actions/azurestorage.js` type: change rationale: Execute the next bounded, logging-only slice by normalizing selected touched-function logs to `consoleLogger` for consistency with current helper/error logging style. impact: Observability consistency improvement only; no API/route behavior or payload contract changes. status: completed Summary: - In previously touched helper-consumer functions only: - `getProgressBlobs` - `getRepsFilesBlobs` - Replaced selected direct `console.log(...)` calls with `consoleLogger(...)`: - progress blob path-parts trace - per-blob name trace in reps file listing - final `blobObj` trace in reps file listing - Scope intentionally excludes broader file-wide logging normalization to keep risk bounded. Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Optional next bounded slice: prune currently-unused local `blobDocumentType` variables in the same touched functions (readability-only, no behavior change). --- ### CL-086: TASK22269 Slice B1.11 — azurestorage touched-function unused-local prune date: 2026-03-26 author: Cline scope: `actions/azurestorage.js` type: change rationale: Execute the next bounded readability-only slice by removing now-unused local variables left in recently touched helper-consumer functions. impact: Maintainability/readability improvement only; no API/route behavior changes. status: completed Summary: - Removed unused local `blobDocumentType` declarations from: - `getBlobs` - `getRepsFilesBlobs` - No object shape, query generation, hash metadata logic, or routing behavior changed. Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Optional next bounded slice: align remaining low-risk direct `console.log` calls in these functions to `consoleLogger` only where already touched and safe. --- ### CL-087: TASK22269 Slice B1.12 — azurestorage touched-function path assembly helper reuse date: 2026-03-26 author: Cline scope: `actions/azurestorage.js` type: change rationale: Execute the next bounded maintainability slice by reusing existing local query-path helpers for touched `filepath`/`deletepath` assembly, reducing repeated literal concatenation. impact: Readability/consistency improvement only; preserves query parameter values and route behavior. status: completed Summary: - In touched functions: - `getBlobs` - `getRepsFilesBlobs` - Replaced inline `filepath` string concatenation with `buildDownloadBlobQueryPath(...)`. - Replaced inline `deletepath` string concatenation with `buildDeleteBlobQueryPath(...)`. - Preserved previous encoding behavior where required by passing explicit options: - kept non-encoded `casefolderID`/`blobname` behavior in `getRepsFilesBlobs.deletepath` via helper options. Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Optional next bounded slice: targeted helper-consumer tidy in the same functions for any remaining repeated query-path literals outside touched object fields. --- ### CL-088: TASK22269 Slice B1.13 — azurestorage touched-function caseObj helper reuse date: 2026-03-26 author: Cline scope: `actions/azurestorage.js` type: change rationale: Execute the next bounded readability slice by centralizing repeated case-object path composition in touched helper-consumer functions. impact: Maintainability/readability improvement only; no route/query behavior changes. status: completed Summary: - Added local helper `buildCaseObjectPath(casefolderID)`. - Replaced repeated `caseObj` string assembly in touched functions: - `getBlobs` - `getProgressBlobs` - Preserved existing `caseObj` output format (`/_case.json`). Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Optional next bounded slice: continue tiny helper reuse in touched functions only if any duplicated path literals remain and can be reduced without behavior change. --- ### CL-089: TASK22269 Slice B1.14 — azurestorage touched-function contentLength local reuse date: 2026-03-26 author: Cline scope: `actions/azurestorage.js` type: change rationale: Execute the next tiny bounded readability slice by reusing local `contentLength` values in touched helper-consumer functions to reduce repeated property access and keep object assembly consistent. impact: Maintainability/readability improvement only; no route/query/output behavior changes. status: completed Summary: - In touched functions: - `getBlobs` - `getProgressBlobs` - `getRepsFilesBlobs` - Added local `contentLength` variable (`blob.properties.contentLength`) per loop iteration. - Replaced repeated inline `blob.properties.contentLength` assignments in object assembly with the local variable. - Preserved field contracts (`contentLength`, `size`) and values. Validation: - `npm run lint` -> pass with warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors) - `node tests/phase22/index.test.cjs` -> pass - `node tests/phase7/service-behaviour.test.cjs` -> pass (13/13) Follow-ups: - Optional next bounded slice: stop or switch scope; touched-function micro-tidies in this area are now largely exhausted. --- ### CL-090: uploadsinglefile API batch upload chunking (10 files per pass) date: 2026-04-02 author: Cline scope: `pages/api/file/uploadsinglefile.js` type: change rationale: Prevent oversized single-pass uploads by splitting validated files into bounded batches and invoking existing upload logic per batch. impact: Upload flow now processes validated files in deterministic chunks of 10 while preserving existing hash guards, validation behavior, and response contract (`data`, `invalidFiles`). status: completed Summary: - Added `MAX_FILES_PER_UPLOAD_BATCH = 10` in `uploadsinglefile` API route. - Replaced single `uploadSingleFile(...)` invocation with chunked processing: - converts allowed files object to entries - slices into batches of 10 - awaits `uploadSingleFile(...)` once per batch - aggregates batch results into one `data` array for response - Kept existing error handling unchanged (`UPLOAD_SINGLE_FILE_FAILED` on catch). Validation: - `npx eslint pages/api/file/uploadsinglefile.js` -> executed with no lint output. Follow-ups: - Optional: add a focused API contract/unit test to assert that 11+ files cause multiple `uploadSingleFile` invocations with max chunk size 10. --- ### CL-091: uploadsinglefile client-side batch upload chunking parity (10 files per pass) date: 2026-04-02 author: Cline scope: `actions/services/documentDirectService.js` type: change rationale: Ensure client upload flow aligns with server batching requirement by splitting outbound `uploadsinglefile` requests into chunks of 10 files. impact: Client now sends multiple sequential API requests (max 10 files each) and merges per-chunk responses into one contract-compatible payload (`data`, `invalidFiles`) for existing UI handlers. status: completed Summary: - Added `MAX_FILES_PER_UPLOAD_BATCH = 10` to document direct service. - Updated `uploadSingleFile(filesObj, containerID, casefolderID)` to: - split selected files into batches of 10 - create a fresh `FormData` per batch - call `/api/file/uploadsinglefile` once per batch (sequential `await`) - aggregate `data` and `invalidFiles` from all chunk responses - Preserved function return shape used by current upload UIs. Validation: - `npx eslint pages/api/file/uploadsinglefile.js actions/services/documentDirectService.js` -> executed with no lint output. Follow-ups: - Optional: add a focused service-behaviour test that verifies `uploadSingleFile` issues N requests for N/10 chunks and merges all chunk responses. --- ### CL-092: per-chunk upload UI progress updates (new appeal + representations) date: 2026-04-02 author: Cline scope: `actions/services/documentDirectService.js`, `components/elements/index.js`, `components/case/representation/representationElements.js` type: change rationale: Update UX so upload progress reflects completed chunks incrementally instead of waiting for all chunk requests to finish. impact: Upload status message now updates after each chunk completes, showing users progressive completion for large multi-file uploads while preserving existing response/error contracts. status: completed Summary: - Extended `uploadSingleFile(...)` service signature with optional callback support: - new `options` argument - invokes `options.onChunkComplete(...)` after each chunk upload - emits cumulative counters (`cumulativeUploaded`, `cumulativeInvalid`, `processedFiles`, chunk index metadata) - Wired per-chunk UI progress updates in both upload entry points: - `components/elements/index.js` - `components/case/representation/representationElements.js` - Both now pass `onChunkComplete` and update `uploadCountMessage` from cumulative uploaded count as each chunk finishes. Validation: - `npx eslint pages/api/file/uploadsinglefile.js actions/services/documentDirectService.js components/elements/index.js components/case/representation/representationElements.js` -> executed with no lint output. Follow-ups: - Optional: add a focused UI behaviour test to assert upload progress increments per completed chunk for >10 file uploads. --- ### CL-093: upload progress message format `X of Y` during chunked uploads date: 2026-04-02 author: Cline scope: `components/elements/index.js`, `components/case/representation/representationElements.js` type: change rationale: User requested clearer in-progress feedback showing uploaded count relative to total files (e.g. `10 of 30`) during chunked uploads. impact: Upload UI now shows progressive message in `X of Y` format while upload is in flight, improving clarity for large batch uploads. status: completed Summary: - Added `totalUploadFiles` state in both upload UIs (new appeal + representations). - In-progress upload message now renders as: - `${uploadCountMessage} of ${totalUploadFiles}` - Upload start now initializes as `0 of Y` and updates after each completed chunk callback. - Empty-drop/reset path clears both counters to avoid stale totals. Validation: - `npx eslint actions/services/documentDirectService.js components/elements/index.js components/case/representation/representationElements.js` -> executed with no lint output. Follow-ups: - Optional: localize a dedicated `upload-progress-x-of-y` translation key if copy needs stronger grammatical control per locale. --- ### CL-094: 22500 `components/elements/index.js` Phase 2 bounded cleanup (remove dead `renderField`) date: 2026-04-07 author: Cline scope: `components/elements/index.js` type: change rationale: Execute the next smallest low-risk Phase 2 slice by removing the local `renderField` utility after confirming it is unused in the repo. impact: No behavior change intended; dead code removal only. No auth/security/middleware/API changes. EN/CY and accessibility behavior remain unchanged. status: completed Summary: - Confirmed `renderField` had no usages outside its declaration. - Removed the unused local `renderField` function from `components/elements/index.js`. - Kept all field component exports, routing, and existing render paths unchanged. Validation: - `npx eslint components/elements/index.js` -> pass Follow-ups: - Continue Phase 2 with one bounded no-behavior-change slice, likely next lowest-risk renderer extraction from `components/elements/index.js`. --- ### CL-095: 22500 `components/elements/index.js` hook-order hotfix (`MultiLinefield`) date: 2026-04-07 author: Cline scope: `components/elements/index.js` type: change rationale: Fix runtime React warning caused by conditional hook execution path in `MultiLinefield` after dead-code cleanup. impact: No functional behavior change intended; resolves Rules of Hooks ordering warning by making label translation hook usage unconditional per render. status: completed Summary: - Root cause: `FieldsTranslations(props.label)` (which internally uses `useRouter`) was invoked within conditional render branches in `MultiLinefield`, causing hook order mismatch when branch conditions changed. - Fix: precomputed `translatedLabel` once in `MultiLinefield` render body and reused in both branches. - Kept EN/CY text resolution logic and rendered output unchanged. Validation: - `npx eslint components/elements/index.js` -> pass Follow-ups: - Continue bounded Phase 2 slices; when touching field components, prefer top-level computed hook-backed values reused across conditional branches. --- ### CL-096: 22500 `RenderSubFields` render-phase update warning hotfix date: 2026-04-07 author: Cline scope: `components/elements/fields/renderSubFields.js` type: change rationale: Fix React warning about updating parent-connected state during `RenderSubFields` render. impact: No intended behavior change; initial empty FieldArray row initialization moved out of render phase to effect phase to satisfy React rendering constraints. status: completed Summary: - Root cause: `fields.length == 0 && fields.push({})` executed inside render, triggering state updates while rendering `RenderSubFields`. - Fix: moved initial row insertion into `useEffect`, guarded by `fields.length === 0`. - Preserved existing UX intent: ensure at least one subfield row appears when array starts empty. Validation: - `npx eslint components/elements/fields/renderSubFields.js` -> pass Follow-ups: - Keep redux-form `fields.push/remove` calls event/effect-driven (not render-driven) in future slices. --- ### CL-097: 22500 `FieldArrayForm` render-phase dispatch warning hotfix date: 2026-04-07 author: Cline scope: `components/elements/index.js` type: change rationale: Fix React warning caused by dispatching redux-form state updates during `FieldArrayForm` render. impact: No intended behavior change; clearing hidden FieldArray values remains intact but now executes in effect phase instead of render phase. status: completed Summary: - Root cause: `dispatch(change("appealForm", name, null))` was called inline in render when parent condition was false. - Fix: moved that dispatch into `useEffect` guarded by `!showIfHasParentShowValue`. - Added `useEffect` import in `components/elements/index.js`. Validation: - `npx eslint components/elements/index.js` -> pass Follow-ups: - Continue avoiding dispatch/state mutations inside render for field visibility toggles. --- ### CL-098: 22500 `FieldArrayForm` bounded dead-code cleanup date: 2026-04-07 author: Cline scope: `components/elements/index.js` type: change rationale: Continue bounded Phase 2 cleanup with a lowest-risk slice by removing unused locals/destructured props in `FieldArrayForm`. impact: No intended behavior change; purely removes unused values left from legacy implementation. status: completed Summary: - Removed unused destructured props from `FieldArrayForm`: `label`, `validation`, `maxFieldLength`. - Removed no-op/dead lines in `FieldArrayForm`: - redundant boolean expression line - unused `parentFieldShowOnValue;` expression - unused `handleSubmit/pristine/reset/submitting` destructure - Kept visibility logic, effect-driven clearing behavior, and `FieldArray` rendering path unchanged. Validation: - `npx eslint components/elements/index.js` -> pass Follow-ups: - Continue Phase 2 with one bounded slice at a time; next low-risk target can be similar dead-code/no-op cleanup in another isolated renderer block. --- ### CL-099: 22500 `components/elements/index.js` bounded extraction bundle (`RenderFileUpload` + `FieldArrayForm`) date: 2026-04-07 author: Cline scope: `components/elements/index.js`, `components/elements/fields/renderFileUpload.js`, `components/elements/fields/fieldArrayForm.js` type: change rationale: Execute a slightly larger but still bounded Phase 2 slice by extracting two self-contained blocks from the monolith (`RenderFileUpload` and `FieldArrayForm`) into dedicated field modules. impact: No intended behavior change; preserves EN/CY output, upload flow, and accessibility semantics while reducing `index.js` size/coupling. status: completed Summary: - Added `components/elements/fields/renderFileUpload.js` and moved the full existing `RenderFileUpload` implementation unchanged. - Added `components/elements/fields/fieldArrayForm.js` and moved the full existing `FieldArrayForm` implementation unchanged. - Updated `components/elements/index.js` imports to consume extracted modules. - Removed inline `RenderFileUpload`/`FieldArrayForm` implementations and related now-unused imports/constants from `index.js`. Validation: - `npx eslint components/elements/index.js components/elements/fields/renderFileUpload.js components/elements/fields/fieldArrayForm.js` -> pass Follow-ups: - Continue Phase 2 with bounded renderer/module extractions from `components/elements/index.js` (one cohesive bundle per commit). --- ### CL-100: 22500 `components/elements/index.js` helper normalization (validation messages + visibility checks) date: 2026-04-07 author: Cline scope: `components/elements/index.js` type: change rationale: Apply the requested next bounded refactor slice by consolidating repeated validation message setup and parent-field visibility logic into shared local helpers. impact: No intended behavior change; EN/CY and accessibility behavior preserved while reducing repeated logic and future drift risk. status: completed Summary: - Added `getValidationMessages(t)` helper for repeated `required/emoji/postcode` message retrieval. - Added visibility helpers: - `hasParentFieldValue(...)` - `isVisibleByEquality(...)` - `isVisibleByInclusion(...)` - Replaced repeated inline visibility and validation-message setup across field wrappers with helper usage (Textfield, MultiLinefield, RichMultiLinefield, DateFieldPicker, YesNofield, Radiofield, NumericField, DecimalField). - Kept existing field render paths, conditions, and validation calls intact. Validation: - `npx eslint components/elements/index.js` -> pass Follow-ups: - Continue bounded no-behavior-change slices by removing dead locals/comments and extracting one additional low-risk field wrapper at a time. --- ### CL-101: 22500 `PickList` wrapper extraction from `components/elements/index.js` date: 2026-04-08 author: Cline scope: `components/elements/index.js`, `components/elements/fields/pickListField.js` type: change rationale: Execute one bounded Phase 2 renderer/wrapper extraction slice by moving the `PickList` wrapper out of the elements monolith into a dedicated field module. impact: No intended behavior change; preserves existing EN/CY translation behavior and validation wiring while reducing `index.js` size/coupling. status: completed Summary: - Added `components/elements/fields/pickListField.js` and moved the existing `PickList` wrapper implementation. - Updated `components/elements/index.js` to import/export `PickList` from the new field module. - Removed inline `PickList` wrapper implementation from `index.js`. - Removed now-unused `RenderPickList` import from `index.js` after extraction. Validation: - `npx eslint components/elements/index.js components/elements/fields/pickListField.js` -> pass Follow-ups: - Continue bounded no-behavior-change slices by extracting one additional low-risk wrapper (e.g., `CheckBoxfield`) or removing dead locals/debug logging in place. --- ### CL-102: 22500 `components/elements/index.js` dead/debug-only cleanup slice date: 2026-04-08 author: Cline scope: `components/elements/index.js` type: change rationale: Execute requested bounded cleanup slice by removing dead code and debug-only artifacts from the elements monolith without changing behavior. impact: No intended behavior change; EN/CY and accessibility behavior preserved while reducing noise and unused code paths. status: completed Summary: - Removed debug-only runtime log in `CheckBoxfield` (`console.log(props)`). - Removed unused/dead locals and helpers inside `components/elements/index.js`, including: - top-level unused imports (`axios`, `pickListLookup`, `setFileCount` action import, redux hooks import) - unused local validators and helpers in wrappers (e.g., unused `required`/`postcode`/`normalizeDecimal` variants) - unused placeholder constant `RenderCaseID` - unused local fallbacks in `FileUploadField` (`uploadCount`, local `setFileCount`) - Kept functional field wiring, labels/translations, and validation behavior in active render paths unchanged. Validation: - `npx eslint components/elements/index.js` -> pass Follow-ups: - Continue bounded no-behavior-change slices only (e.g., extract one additional low-risk wrapper such as `CheckBoxfield`). --- ### CL-103: 22500 wrapper extraction bundle (`CheckBoxfield`, `DateFieldPicker`, `YesNofield`) date: 2026-04-08 author: Cline scope: `components/elements/index.js`, `components/elements/fields/{checkBoxField,dateFieldPicker,yesNoField}.js` type: change rationale: Execute the requested bundled wrapper slice by extracting wrappers 1/2/3 in one commit while keeping behavior unchanged. impact: No intended behavior change; keeps EN/CY output, visibility logic, and accessibility structure intact while reducing `components/elements/index.js` size. status: completed Summary: - Added `components/elements/fields/checkBoxField.js` and moved `CheckBoxfield` wrapper. - Added `components/elements/fields/dateFieldPicker.js` and moved `DateFieldPicker` wrapper logic. - Added `components/elements/fields/yesNoField.js` and moved `YesNofield` wrapper logic. - Updated `components/elements/index.js` to import/export these wrappers from field modules. - Removed inline implementations of `CheckBoxfield`, `DateFieldPicker`, and `YesNofield` from `index.js`. Validation: - `npx eslint components/elements/index.js components/elements/fields/checkBoxField.js components/elements/fields/dateFieldPicker.js components/elements/fields/yesNoField.js` -> pass Follow-ups: - Remaining wrappers can continue as bounded slices (`Radiofield`, `NumericField`, `DecimalField`) if required. --- ### CL-104: 22500 wrapper extraction bundle (`Radiofield`, `NumericField`, `DecimalField`) date: 2026-04-08 author: Cline scope: `components/elements/index.js`, `components/elements/fields/{radioField,numericField,decimalField}.js` type: change rationale: Continue Phase 2 with the next bounded wrapper bundle by extracting wrappers 4/5/6 from `components/elements/index.js` into dedicated field modules without behavior change. impact: No intended behavior change; preserves EN/CY behavior, validation wiring, and accessibility semantics while reducing monolith size. status: completed Summary: - Added `components/elements/fields/radioField.js` for `Radiofield`. - Added `components/elements/fields/numericField.js` for `NumericField`. - Added `components/elements/fields/decimalField.js` for `DecimalField`. - Updated `components/elements/index.js` to import/export these wrappers from field modules. - Removed inline `Radiofield`, `NumericField`, and `DecimalField` implementations from `index.js`. Validation: - `npx eslint components/elements/index.js components/elements/fields/radioField.js components/elements/fields/numericField.js components/elements/fields/decimalField.js` -> pass Follow-ups: - Next bounded wrappers (if needed): `ReadOnlyfield`/remaining small wrappers or additional dead-code cleanup slices.