Restore readable ID and selfie previews after successful photo selection, and identify the underlying rendering failure behind the misleading damaged-image message.
Approach
Reproduced the web failure with synthetic valid image content. Create a compatible typed-byte copy at the preview boundary while keeping the Photo model immutable, bounded decoding, replacement/removal and cache cleanup. Use accurate EN/RU preview-recovery copy with an isolated live-region announcement. Preserve the DTO → mapper → service → model → provider → UI architecture and existing KYC journey measurement.
Acceptance criteria
The underlying exception and cause are reproduced and documented.
Accepted JPEG/PNG photos render in ID, selfie and review previews, including replacement and navigation.
Photo/model immutability and preview cache cleanup remain intact; no image data or raw exception payloads enter telemetry.
Regression tests cover real decoding and relevant error/lifecycle paths on native and web.
Changed Dart files pass format, app analyzer passes, all six Chrome regressions pass, and make test-frontend passes.
Full contribution quality review completed; findings fixed if present.
PR merged with user authorization, clean main pulled, and frontend service rebuilt and verified.
Cause: Flutter Web's browser decoder rejected _UnmodifiableUint8ListView as incompatible with NativeUint8List. Validation had decoded the original bytes before Photo wrapped them. A compatible preview copy fixes the failure without weakening the domain model.
Final quality review covered the entire seven-file contribution and found no additional source defects. Current main, including birthday/signup/account setup changes, was integrated before validation. The two-file Dart format check, frontend/app analyzer, all six Chrome preview regressions and all 240 tests in make test-frontend passed. The earlier isolated branch had 228 passing tests and a successful release web build/Wasm dry run. Review evidence and limitations are committed in docs/ux/photo-preview.md.
Rollout: primary checkout /Users/stephan/Documents/Projects/sxchnge is clean on main and matches origin/main at the merge commit. The repository stable resolver was rerun; Flutter 3.47.7, digest-pinned Ubuntu 26.04 and Caddy 2.11.7-alpine were used. docker compose ... build --pull frontend succeeded, followed by up -d --no-deps --force-recreate --wait --wait-timeout 120 frontend. Only frontend was recreated; the other service container IDs and healthy states were unchanged.
Running frontend image: sha256:9b0a03198d126b043d4cd4816d4dec97a550bc49da1feff5c900f9059c1d1af0. Container is healthy. CA-verified HTTPS requests to https://localhost:5126/ and /api/v1/health returned 200. Served main.dart.js contains the new preview fallback and matches the runtime image file, SHA-256 89ea03f0caddbd5b3da8a41a68bddd41277b0cd00688df0f21d4c2b0763c7459. Generated local pins and build outputs remain ignored.
Existing submission/abandonment measurement remains intact; preview-only paint failures are not separately counted. Safari and native assistive-technology testing remain release checks. No photo contents, form values, filenames or raw errors were added to telemetry.
### Goal
Restore readable ID and selfie previews after successful photo selection, and identify the underlying rendering failure behind the misleading damaged-image message.
### Approach
Reproduced the web failure with synthetic valid image content. Create a compatible typed-byte copy at the preview boundary while keeping the Photo model immutable, bounded decoding, replacement/removal and cache cleanup. Use accurate EN/RU preview-recovery copy with an isolated live-region announcement. Preserve the DTO → mapper → service → model → provider → UI architecture and existing KYC journey measurement.
### Acceptance criteria
- [x] The underlying exception and cause are reproduced and documented.
- [x] Accepted JPEG/PNG photos render in ID, selfie and review previews, including replacement and navigation.
- [x] Photo/model immutability and preview cache cleanup remain intact; no image data or raw exception payloads enter telemetry.
- [x] Regression tests cover real decoding and relevant error/lifecycle paths on native and web.
- [x] Changed Dart files pass format, app analyzer passes, all six Chrome regressions pass, and make test-frontend passes.
- [x] Full contribution quality review completed; findings fixed if present.
- [x] PR merged with user authorization, clean main pulled, and frontend service rebuilt and verified.
### Notes
Primary module: kyc; frontend only. Owner: tech; existing frontend label and SXCHNGE project. Branch: `kyc-69`. Delivery: [PR #71](https://git.sendico.io/tech/sxchnge/pulls/71), merged at `de449d53bfb8fa9897a54cc5e40cdd605c133f8f`.
Cause: Flutter Web's browser decoder rejected `_UnmodifiableUint8ListView` as incompatible with `NativeUint8List`. Validation had decoded the original bytes before Photo wrapped them. A compatible preview copy fixes the failure without weakening the domain model.
Final quality review covered the entire seven-file contribution and found no additional source defects. Current main, including birthday/signup/account setup changes, was integrated before validation. The two-file Dart format check, frontend/app analyzer, all six Chrome preview regressions and all 240 tests in `make test-frontend` passed. The earlier isolated branch had 228 passing tests and a successful release web build/Wasm dry run. Review evidence and limitations are committed in `docs/ux/photo-preview.md`.
Rollout: primary checkout `/Users/stephan/Documents/Projects/sxchnge` is clean on main and matches origin/main at the merge commit. The repository stable resolver was rerun; Flutter 3.47.7, digest-pinned Ubuntu 26.04 and Caddy 2.11.7-alpine were used. `docker compose ... build --pull frontend` succeeded, followed by `up -d --no-deps --force-recreate --wait --wait-timeout 120 frontend`. Only frontend was recreated; the other service container IDs and healthy states were unchanged.
Running frontend image: `sha256:9b0a03198d126b043d4cd4816d4dec97a550bc49da1feff5c900f9059c1d1af0`. Container is healthy. CA-verified HTTPS requests to `https://localhost:5126/` and `/api/v1/health` returned 200. Served main.dart.js contains the new preview fallback and matches the runtime image file, SHA-256 `89ea03f0caddbd5b3da8a41a68bddd41277b0cd00688df0f21d4c2b0763c7459`. Generated local pins and build outputs remain ignored.
Existing submission/abandonment measurement remains intact; preview-only paint failures are not separately counted. Safari and native assistive-technology testing remain release checks. No photo contents, form values, filenames or raw errors were added to telemetry.
tech
added the frontend label 2026-10-23 10:16:50 +00:00
tech
self-assigned this 2026-10-23 10:16:50 +00:00
tech
added this to the SXCHNGE project 2026-10-23 10:16:50 +00:00
Underlying error reproduced in Flutter Web with a synthetic valid PNG: TypeError: Instance of '_UnmodifiableUint8ListView': type '_UnmodifiableUint8ListView' is not a subtype of type 'NativeUint8List'. The stack runs through Uint8ListToJSUint8Array.toJS → CanvasKit browser decoder → MemoryImage/ResizeImage. Validation decodes the original typed bytes; Photo then wraps its copy in an unmodifiable view, which the web preview decoder cannot consume.
The preview now owns a compatible Uint8List copy while Photo stays immutable. Localized preview-only failure copy replaces the damaged-file accusation and preserves replacement/removal plus live-region feedback. Six browser regression tests now pass, covering accepted JPEG/PNG rendering, immutability, replacement/disposal cache eviction, review re-entry and EN/RU recovery at 320px/1.6 text scale. Final full frontend suite and release build are in progress; format and app analyzer have passed. Birthday work on kyc-67 remains untouched.
Underlying error reproduced in Flutter Web with a synthetic valid PNG: `TypeError: Instance of '_UnmodifiableUint8ListView': type '_UnmodifiableUint8ListView' is not a subtype of type 'NativeUint8List'`. The stack runs through `Uint8ListToJSUint8Array.toJS` → CanvasKit browser decoder → MemoryImage/ResizeImage. Validation decodes the original typed bytes; Photo then wraps its copy in an unmodifiable view, which the web preview decoder cannot consume.
The preview now owns a compatible Uint8List copy while Photo stays immutable. Localized preview-only failure copy replaces the damaged-file accusation and preserves replacement/removal plus live-region feedback. Six browser regression tests now pass, covering accepted JPEG/PNG rendering, immutability, replacement/disposal cache eviction, review re-entry and EN/RU recovery at 320px/1.6 text scale. Final full frontend suite and release build are in progress; format and app analyzer have passed. Birthday work on kyc-67 remains untouched.
Completed the requested contribution-quality review across the full seven-file PR. No additional source defects were found. Integrated current main (ec4115d) and reran the two-file Dart format check, frontend/app analyzer, all six Chrome preview regression tests, and make test-frontend (240 tests); all passed. Review evidence is committed in docs/ux/photo-preview.md.
PR #71 was merged with user authorization. The primary checkout is being fast-forwarded to clean main and only the frontend service is being rebuilt using freshly resolved stable releases and digest-pinned inputs. Runtime checks will be recorded after replacement.
Completed the requested contribution-quality review across the full seven-file PR. No additional source defects were found. Integrated current main (ec4115d) and reran the two-file Dart format check, frontend/app analyzer, all six Chrome preview regression tests, and `make test-frontend` (240 tests); all passed. Review evidence is committed in docs/ux/photo-preview.md.
PR #71 was merged with user authorization. The primary checkout is being fast-forwarded to clean main and only the frontend service is being rebuilt using freshly resolved stable releases and digest-pinned inputs. Runtime checks will be recorded after replacement.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Goal
Restore readable ID and selfie previews after successful photo selection, and identify the underlying rendering failure behind the misleading damaged-image message.
Approach
Reproduced the web failure with synthetic valid image content. Create a compatible typed-byte copy at the preview boundary while keeping the Photo model immutable, bounded decoding, replacement/removal and cache cleanup. Use accurate EN/RU preview-recovery copy with an isolated live-region announcement. Preserve the DTO → mapper → service → model → provider → UI architecture and existing KYC journey measurement.
Acceptance criteria
Notes
Primary module: kyc; frontend only. Owner: tech; existing frontend label and SXCHNGE project. Branch:
kyc-69. Delivery: PR #71, merged atde449d53bfb8fa9897a54cc5e40cdd605c133f8f.Cause: Flutter Web's browser decoder rejected
_UnmodifiableUint8ListViewas incompatible withNativeUint8List. Validation had decoded the original bytes before Photo wrapped them. A compatible preview copy fixes the failure without weakening the domain model.Final quality review covered the entire seven-file contribution and found no additional source defects. Current main, including birthday/signup/account setup changes, was integrated before validation. The two-file Dart format check, frontend/app analyzer, all six Chrome preview regressions and all 240 tests in
make test-frontendpassed. The earlier isolated branch had 228 passing tests and a successful release web build/Wasm dry run. Review evidence and limitations are committed indocs/ux/photo-preview.md.Rollout: primary checkout
/Users/stephan/Documents/Projects/sxchngeis clean on main and matches origin/main at the merge commit. The repository stable resolver was rerun; Flutter 3.47.7, digest-pinned Ubuntu 26.04 and Caddy 2.11.7-alpine were used.docker compose ... build --pull frontendsucceeded, followed byup -d --no-deps --force-recreate --wait --wait-timeout 120 frontend. Only frontend was recreated; the other service container IDs and healthy states were unchanged.Running frontend image:
sha256:9b0a03198d126b043d4cd4816d4dec97a550bc49da1feff5c900f9059c1d1af0. Container is healthy. CA-verified HTTPS requests tohttps://localhost:5126/and/api/v1/healthreturned 200. Served main.dart.js contains the new preview fallback and matches the runtime image file, SHA-25689ea03f0caddbd5b3da8a41a68bddd41277b0cd00688df0f21d4c2b0763c7459. Generated local pins and build outputs remain ignored.Existing submission/abandonment measurement remains intact; preview-only paint failures are not separately counted. Safari and native assistive-technology testing remain release checks. No photo contents, form values, filenames or raw errors were added to telemetry.
Underlying error reproduced in Flutter Web with a synthetic valid PNG:
TypeError: Instance of '_UnmodifiableUint8ListView': type '_UnmodifiableUint8ListView' is not a subtype of type 'NativeUint8List'. The stack runs throughUint8ListToJSUint8Array.toJS→ CanvasKit browser decoder → MemoryImage/ResizeImage. Validation decodes the original typed bytes; Photo then wraps its copy in an unmodifiable view, which the web preview decoder cannot consume.The preview now owns a compatible Uint8List copy while Photo stays immutable. Localized preview-only failure copy replaces the damaged-file accusation and preserves replacement/removal plus live-region feedback. Six browser regression tests now pass, covering accepted JPEG/PNG rendering, immutability, replacement/disposal cache eviction, review re-entry and EN/RU recovery at 320px/1.6 text scale. Final full frontend suite and release build are in progress; format and app analyzer have passed. Birthday work on kyc-67 remains untouched.
Completed the requested contribution-quality review across the full seven-file PR. No additional source defects were found. Integrated current main (
ec4115d) and reran the two-file Dart format check, frontend/app analyzer, all six Chrome preview regression tests, andmake test-frontend(240 tests); all passed. Review evidence is committed in docs/ux/photo-preview.md.PR #71 was merged with user authorization. The primary checkout is being fast-forwarded to clean main and only the frontend service is being rebuilt using freshly resolved stable releases and digest-pinned inputs. Runtime checks will be recorded after replacement.