16 KiB
Phase 8 — Dashboard customisation acceptance
Accepted with the qualifications below on22 October2026 (local time). This report qualifies the implementation against the accepted Phase7 baseline ef94d579cbfec62d1ac38346f556f80276cee95a. Work is confined to feature/phase8-dashboard-customisation; accepted product source is 2f6227fb4f9a6cc61838e8afde9e2dafd00bd428. The final complete browser run exercised the same815 selected source/test, Release-assembly and static-export inputs recorded at its entry, with zero subsequent differences. Documentation and the separate performance diagnostic follow that source checkpoint.
Independent decisions
| Decision | Status | Boundary |
|---|---|---|
| Phase 8 completion | CONDITIONAL GO | All requested capabilities are implemented; complete local regression and focused repairs pass. Human/device/provider qualifications below remain open. |
| Phase 9 readiness | CONDITIONAL GO | Whole-application QA may proceed with the explicit handoff and retained obligations below. Phase9 has not started. |
| Production release | NO-GO | No separate release process has cleared the retained mandatory gates. |
Delivered scope and checkpoints
The personal dashboard now has one explicit, labelled editor and a live preview. All nine existing sections can be hidden/restored and reordered. The eight resizable reports support standard/full width; summary cards remain full width. A central typed catalogue supplies defaults, stable IDs, allowed sizes and normalization. Reading order follows the canonical DOM order at every width. Analytics retains its independent reporting view and does not load personal layout preferences. Administrator views and report data contracts were preserved.
Save waits for an acknowledged owner-scoped API write. Cancel restores the saved layout; Reset changes only the draft after confirmation and still requires Save. Failures retain the draft. Stale revisions offer explicit reload rather than silent overwriting. Empty layouts have an accessible recovery action. Loading/future-schema guards prevent unsafe editing; auth generations and cancellation protect account switches and stale responses. Legacy account-local hidden flags are used only before a server layout exists and sync on the first explicit Save.
| Checkpoint | Result and evidence |
|---|---|
| P8-00 | Complete, published: fresh baseline suites, catalogue/design, architecture and Phase 7 prerequisite review; baseline. |
| P8-01 | Complete, published: visibility, draft/save/cancel/reset, errors, empty recovery, EN/NB; UI checkpoint. |
| P8-02 | Complete, published: existing drag handle, named Earlier/Later controls, focus/live position, discrete sizes, responsive canonical grid; layout checkpoint. |
| P8-03 | Complete, published: additive persistence, strict HTTP contract, optimistic concurrency and isolation; backend evidence. |
| P8-04 | Complete, published: native browser matrices, keyboard, emulated touch, exact values, axe triage and populated sizing regression; responsive/accessibility evidence. |
| P8-05 | Complete local acceptance: backend/frontend/ordinary browser/contracts/sidecar, types/lint/build/security,57-group reconciliation, final decisions and handoff; published by the acceptance commit containing this report. |
P8-01/02 share their integrated UI checkpoint because the same editor/render owner implements visibility, order and sizing. Persistence was implemented first to support acknowledged end-to-end saves. These are sequencing/documentation deviations, not omitted capabilities. No dependencies, dashboard framework or generic settings service were added. No main merge, production deployment, production migration, AI model change or destructive live-data operation occurred.
Contract, security and evolution
GET/PUT /api/auth/preferences/dashboard derives the account from local authentication. The version1 payload is {version, revision, widgets:[{id,visible,size}]}; revision0 with an empty list denotes an unsaved account. The additive migration adds nullable layout JSON and a default-zero revision to the existing account owner. Strict allowed IDs, boolean/size/version validation, duplicate rejection, maximum32 entries and an actual16KB byte cap apply even to chunked requests. Preferences contain presentation metadata only and cannot grant data access.
The conditional owner-and-revision update increments revision atomically; concurrent first saves and stale saves conflict with409. The revision read before the body must also match, preventing a future-schema update during a paused body from being downgraded. Unrelated Identity updates cannot replay stale layout columns. Corrupt reads normalize safely; unknown stored IDs are ignored, missing known widgets in saved revisions append hidden, and future schemas remain read-only to older clients. JavaScript-unsafe revisions are rejected. See the full catalogue/evolution contract.
Actual local HTTP and cookie/session browser tests cover anonymous401, ordinary-user admin403, A/B ownership, attempted account override, stale session/CSRF, independent preference fields and logout/login/fresh-context persistence. Backend tests use a test auth handler; browser tests exercise real local cookies/session context/CSRF. Neither establishes deployed identity or proxy acceptance. SQLite held-reader/write and simultaneous-save tests pass on WAL; this is finite contention evidence, not permanent immunity. SQLite migration/startup/chain tests pass. MariaDB provider SQL generation passes; MariaDB runtime remains untested because Docker's Linux engine is unavailable.
Executed regression and build evidence
Raw output is retained under .artifacts/phase8/; portable counts, hashes and source identities are in validation.json and source-manifest.json. No retries, skips or flakes are counted as passes in accepted browser lanes. Targeted/standard-contract counts below are separate from the ordinary suite.
| Lane | Actual completed result | Evidence |
|---|---|---|
| Entry backend | 1,060 passed; 0 failed/skipped | baseline/p8-baseline.trx |
| Complete backend after final API repair | 1,084 passed; 0 failed/skipped, including24 new dashboard cases | backend-toctou-full/dashboard-full.trx |
| Entry frontend | 899 tests /101 suites passed; 0 failed/pending | baseline-frontend.json |
| Complete frontend before final salary CSS fix | 917 tests /104 suites passed; 0 failed/pending | frontend-qualified.json |
| Complete frontend after salary fix | 917 tests /104 suites passed; 0 failed/pending,332.201s | frontend-salary.json |
| Previous uninterrupted ordinary browser | 360 passed; 0 failed/skipped/flaky/retried | browser-accepted.json; precedes the final salary sizing fix |
| Final uninterrupted ordinary browser | 360 passed; 0 failed/skipped/flaky/retried,2908.357s | browser-salary-final.json |
| Separate standard browser contracts | 23 passed; 0 failed/skipped/flaky/retried | AI2, auth recovery2, rate limits9, ingress6, PDF admission1, diagnostics3; contract-*.json |
| Populated supported-size diagnostics | 2 passed; 0 failed/skipped/flaky/retried,8 screenshots | salary-green.json; both complete size presets,320/768/1024/1440px |
| Separate250-job performance diagnostic | 1 passed; 0 failed/skipped/flaky/retried | performance-successor.json; desktop/mobile load, edits, acknowledged save, request counts and renderer observations |
| Offline summarizer sidecar | 56 passed; 0 failed/errors/skipped | sidecar.xml, model loading disabled |
| Production frontend export | PASS after final salary fix, explicit local API5302 | salary-build.log; no production deployment |
| Frontend types/lint; browser/diagnostic types | PASS after salary fix | typecheck-salary.log, lint-salary.log, browser-typecheck-salary.log |
Complete backend command: pinned .dotnet/dotnet.exe test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --configuration Release --no-restore with TRX logger. UI commands from job-tracker-ui: node node_modules/jest/bin/jest.js --runInBand --json --outputFile=../.artifacts/phase8/frontend-salary.json, npm run typecheck, npm run lint, npm run build. Build sets NEXT_PUBLIC_API_BASE_URL=http://localhost:5302/api. All shell commands use the repository RTK wrapper.
Ordinary native command: node node_modules/@playwright/test/cli.js test --retries=0 --reporter=list,json; DOTNET_HOST_PATH points to the pinned SDK, PLAYWRIGHT_STATIC_EXPORT=true, PLAYWRIGHT_PREBUILT_EXPORT=true, separate JSON/output paths. Separate contracts use existing configs for AI, auth recovery, rate limits, ingress, PDF and retained Phase5 diagnostics. Populated sizing uses docs/redesign/phase-8/p8-04/diagnostics/playwright.config.ts. Sidecar command from tools/summarizer: .venv/Scripts/python.exe -m pytest -q tests --junitxml=../../.artifacts/phase8/sidecar.xml with SKIP_MODEL_LOAD=1. The extra browser type project includes existing e2e/auth/AI configs and both retained/new diagnostic sources.
Offline security checks pass: tracked-secret scan; supply-chain helpers3; Ollama evaluation helpers5; browser-runtime helpers6; ingress helpers3; Node audit-policy/SMTP contracts15; extension URL contracts3; SBOM generation. Dependency manifests/lockfiles, project files and Docker/compose definitions are unchanged. Live npm/NuGet advisory refresh was not run; inherited NuGet Pkcs high/moderate and development advisory qualifications remain. Docker topology execution was attempted and blocked by the missing Linux engine pipe; static ingress tests are not runtime topology acceptance.
Failed experiments are retained, not erased: absent-feature RED; stale Identity replay RED; initial migration downgrade/fixture failures; future-schema and unsafe-revision RED; paused-body downgrade RED; initial browser API5202/5302 mismatch; interrupted full browser with obsolete five-flag Analytics fixture; editor header-focus RED; misleading pending-save navigation RED; preview-role RED; and salary digit-wrap RED. Their bounded repairs and successful successors are described in the checkpoint reports. No existing functional assertion was weakened to obtain a pass.
Performance assessment
The finite250-job observation measured load to all nine widgets at1105ms/995ms for1440px/320px, a hide/show/resize/reorder sequence at307ms/315ms, and acknowledged Save at170ms/130ms. There were711/716 DOM elements and Chromium reported27.6MB used JavaScript heap at both widths. These are two unthrottled local observations including automation overhead, not comparative Phase7 benchmarks, mobile hardware measurements, capacity/SLA acceptance or sustained drag-frame profiling.
Each load made one read per stats/overview/activity/tags/tag-trends endpoint. Reminders made two existing reads, one for the unchanged shell badge and one for Dashboard; baseline source confirms both predate Phase8. The diagnostic initially failed its incorrect one-reminder expectation, retained in performance-final.json; source/network inspection corrected that fixture expectation and the successor passed. Crucially, hide/show, size, keyboard order and acknowledged Save made zero additional report reads at both widths. The existing unit regression independently proves no report refetch during reorder; native pointer drag passes its functional browser case. This duplicate initial reminder read remains a shared-owner optimization opportunity, not silently described as eliminated.
Source assessment: layout changes are independent of the two existing resource loaders and their stable dependencies; report requests remain aggregate/bounded responses rather than loading250 job entities to render nine widgets. Small existing chart/tag/month computations still execute during view renders; no speculative memoization or query framework was added without a measured need. Full rerender counts, chart CPU/frame breakdown, sustained drag stress and physical mobile resource usage remain unmeasured and belong to broader Phase9 performance qualification. The measurements provide finite usability evidence, not proof against every noticeable slowdown.
Responsive, accessibility and preservation
Native Chromium covers EN/Bokmål, light/dark, keyboard order/focus, desktop drag, emulated touch alternatives, errors and readback. Targeted editor widths include320/390/768/1440px; retained reports include1024/1920px. All populated widgets at both supported size presets were checked at320/768/1024/1440px for root overflow and contained tables/charts. The salary regression checks actual text line rectangles, because overflow alone missed fragmented numbers. No fixed widget height or CSS visual reordering was introduced. Two editor captures and the repaired salary crop were inspected and retained in P8-04.
The final whole-run targeted Dashboard/Analytics/editor axe extraction recorded 10 scans,0 automated violations and64 incomplete node occurrences (63contrast,1drawer focus), with invalid preview semantics removed; full details are in axe.json. Incompletes require manual assessment; zero violations is not WCAG certification. Human screen-reader operation, physical touch/software keyboard, complete actual browser zoom/text enlargement/reflow, other browsers, manual layered contrast/drawer focus, deployed Linux/font/photo/native output and linguistic review remain outstanding. Existing vendor strings and Phase7 qualifications remain.
All40 required scenarios are mapped individually in SCENARIOS.md. The exact57 preservation groups remain 56 PARTIAL / PRES-C11 DEFERRED, with explicit Phase8 impact in PRESERVATION.md. These statuses describe finite evidence and remaining qualifications; they are not upgraded to full acceptance. All33 concrete route patterns remain; the complete App.tsx route owner is byte-identical to the entry baseline. Existing Dashboard values, independent Analytics periods/loading/failures/links, administration and wider application tests are retained. No route or protected capability was intentionally removed.
Phase 9 handoff and production withholding
Phase9 may use this branch's published implementation and exact final source evidence to begin whole-application QA under the conditional decision above. No Phase9/10 implementation is part of this work. Carry all40 scenario mappings and57 preservation statuses forward. Prioritize human accessibility/device/zoom/linguistic checks, independent provider/runtime/output checks, broader contention/resilience and performance profiling, and final integration against actual deployment configuration. If widget IDs/availability change, follow the explicit versioned contract; layout metadata must never become an authorization mechanism.
Production remains NO-GO. The previously reported production disk condition, independently verified off-disk backup/restore, ingress/configuration/schema agreement, rollback proof, deployed identity, native/manual output, Qwen/model and withheld P5-13 gates have not been cleared or rechecked by these local tests. They require their separate release-readiness process and owner authorization. A Phase8 acceptance decision cannot clear them.
Source and publication
Published checkpoints: plan 421f902d21c08a814de12d7c32bc6ab8d4c01e15; persistence 5edbe59692ae054dc868b352e69f367efa6bdc3b; paused-body protection a24e6b31593649f9351f48c85cb6ecd71c5b3192; catalogue/state 68ee6ca; integrated editor 77968da90caac73036dfd49fdbe0f47bd913405e; responsive/semantics 960458978587a7503f8fc74063c5ee1e997e2254; final salary repair/size diagnostics 2f6227fb4f9a6cc61838e8afde9e2dafd00bd428. The latter was normally pushed and directly verified. The acceptance checkpoint is the commit containing this report and the separate performance diagnostic; it changes no accepted product bytes. Its exact hash, clean worktree and direct feature-ref equality are verified after commit/push and reported in the completion response, avoiding a self-referential commit hash here. Main remains directly observed at 5f835e54a9b74e6b71418422e28431b2af06453f; no operation targets main.