# Change Log (AI/Human Curated) ## Entry Template ``` date: YYYY-MM-DD author: scope: type: change rationale: impact: status: completed|rolled-back|partial Summary: Validation: Follow-ups: ``` --- ### CL-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.