Files
pedwfrontend/memory-bank/change-log.md
T

4044 lines
184 KiB
Markdown
Raw Blame History

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