fix(ui): verify responsive accessibility and restore Career label
@@ -9,6 +9,7 @@ Every completed logical unit is pushed to `codex/ui-redesign-phase4`, without fo
|
||||
| Current P6-00 baseline and design audit | `7da083c374abcb6b34600f3c6667830d47b14760` | Whitespace/source/document review; pushed normally; HEAD=origin immediately after push, main unchanged |
|
||||
| P6-01 shared semantic/contrast/panel corrections | `a94ea0a4a4695d1c196366ac39793a901485e919` | Final521 units/85 suites, type/lint/build and4 native Settings cases green; normal push, HEAD=origin |
|
||||
| P6-02 cross-application save/retry and localisation corrections | `c135d03602fd273658cfa1c087491c7442060c6a` | Company/language native4/4 with persistence after retry/reload; final521 units; normal push, HEAD=origin |
|
||||
| P6-02 companion: replace historical hidden-error assertion with accessible dialog contract | `81e30e3da9e36e4cb0271122711fddc7b28b75e3` | Four affected theme/locale/width workflows pass; strengthened alert/draft/no-write/focus assertions; normal push, HEAD=origin, main unchanged |
|
||||
|
||||
## Current execution evidence
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ Fetched development HEAD/remote: `9d6d29dba4733778e478909d4ff74a25409b3115`, `co
|
||||
|
||||
- [x] **P6-00:** Review Phase 3/4/5 records, all 57 original PRES contracts and actual source; record surface/state coverage, prioritized findings, preserved dirty intake and baseline. Audit pushed at `7da083c`, remote=HEAD.
|
||||
- [x] **P6-01:** Shared semantic/contrast/tab associations verified; final521 unit cases and4 native panel cases pass. Pushed `a94ea0a`, remote=HEAD; full native cross-route acceptance follows in P6-05.
|
||||
- [ ] **P6-02:** Verify navigation/query/history/source/override and save/retry workflows; finish retained company-dialog error feedback and language persistence feedback with localized tests and native HTTP readback. Review approved AI purpose/provenance/review/conflict patterns without activating withheld work. Commit/push.
|
||||
- [ ] **P6-03:** Collect EN/Bokmål, light/dark, 320–wide desktop, orientation, keyboard, zoom/reflow and all-enabled axe evidence. Triage every remaining violation/incomplete category; inspect representative screenshots. Retain M01–M13 and physical-device requirements. Commit/push.
|
||||
- [x] **P6-02:** Navigation/query/history/source/override and AI boundaries reviewed; company dialog and account-language failures retain drafts/local choice and translated retry. Native4/4 passes including real persistence/reload. Pushed `c135d03`, remote=HEAD.
|
||||
- [x] **P6-03:** Recorded attributed EN/Bokmål, theme, responsive, keyboard, zoom and axe baseline with all incomplete categories retained; inspected fourteen baseline and four label before/after images. Bounded mobile label repair has native RED→GREEN2/2 and final Settings/label6/6. Fresh521 units/types/lint/build pass; integrated acceptance follows in P6-05. Human M01–M13 and physical-device acceptance remain unverified. Push receipt follows in the ledger.
|
||||
- [ ] **P6-04:** Record production bundle bytes and reproducible native route/data/long-CV performance, requests, long tasks/CLS and memory where tooling supports them. Audit shared consumers and O(N) scaling; optimize only a demonstrated bounded cause. Do not invent budgets. Commit/push measured findings.
|
||||
- [ ] **P6-05:** Run fresh full frontend/backend/browser/sidecar/security/HTTP/rendering lanes, explain count changes, reconcile 57 groups, record secret/link/whitespace/build evidence and every commit/push. Report independent Phase 6, production and Phase 7 decisions; prepare migration order and mandatory dependencies. Commit/push final acceptance.
|
||||
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# Phase 6 — Design and UX Review
|
||||
|
||||
## Current execution — 2026-10-11
|
||||
|
||||
The owner's current **P6-00–P6-05** instruction supersedes the seven-checkpoint proposal retained below. Execution started at fetched/synchronized `9d6d29dba4733778e478909d4ff74a25409b3115` on **codex/ui-redesign-phase4**, preserving seven modified source/test files. [Execution plan](EXECUTION_PLAN.md) and [commit log](COMMITS.md) track actual work.
|
||||
|
||||
| Current checkpoint | Deliverable |
|
||||
|---|---|
|
||||
| [P6-00](p6-00/README.md) | Baseline, all requested surfaces and prioritized design consistency register; pushed `7da083c` |
|
||||
| [P6-01](p6-01/CORRECTIONS.md) | Shared semantic, contrast and Settings panel corrections |
|
||||
| [P6-02](p6-02/README.md) | Workflow/error/retry review and approved [AI patterns](p6-02/AI_REVIEW.md) |
|
||||
| [P6-03](p6-03/README.md) | Fresh locale/theme/responsive/keyboard evidence and axe triage |
|
||||
| [P6-04](p6-04/README.md) | Native performance and component reuse review |
|
||||
| [P6-05](p6-05/README.md) | Integrated acceptance, [57-group preservation](p6-05/PRESERVATION.md) and [Phase 7 plan](p6-05/PHASE7_HANDOFF.md) |
|
||||
|
||||
Final decisions and today's fresh counts are in P6-05; inherited results below are attributed history. Production remains **NO-GO**, main unchanged. P5-13, P5-05/followMode, human reader/physical-device and production qualification remain deferred or unverified. No Phase 7/8 implementation or deployment is authorized by this review.
|
||||
|
||||
## Historical transition/planning record
|
||||
|
||||
**Review-planning readiness: CONDITIONAL GO.** Phase 5's implemented local scope can enter bounded design/UX review; the originally planned full scope is NOT COMPLETE and production release remains NO-GO. This is the transition/planning checkpoint, not Phase 7 migration or a release authorization.
|
||||
|
||||
## Verified handoff
|
||||
|
||||
@@ -19,5 +19,6 @@ Baseline `9d6d29d`, 2026-10-11. Current source inspection corroborates the earli
|
||||
| P6-DC13 | Intentional variation | Inverse nav, landing marketing gradient, CV white paper and legitimate Board/document canvas two-dimensional scrolling have distinct purposes. | Retain approved context; app chrome must reflow. No speculative global radius/spacing/gradient replacement. E07/E08/C09. |
|
||||
| P6-DC14 | Approved Phase 7 work | Auth/onboarding/Profile/library/full Documents/mail/Notifications/remaining Settings/Admin/error/dialog migration differs from redesigned representative screens. | Reconcile existing implemented children before Phase 7 plan; legacy presentation is not itself Phase 6 regression. No implementation now. |
|
||||
| P6-DC15 | Deferred qualification | P5-13 has zero configured-target calls/human reviews and withheld review UI; P5-05/followMode also deferred. | Eventual AI UI reuses current/proposed/source scope, review/no-write rejection, existing feedback/draft owner; no model calls or activation; C11/W05. |
|
||||
| P6-DC16 | Responsive/localisation / P2, discovered during fresh P6-03 visual review | Mobile Career section selector clips its floating label: native RED in both NB320/dark and EN390/light places labelTop8px above the clipping navigation container. | Replace control padding with existing spacing as an outer margin and preserve inner width; native geometry, keyboard section navigation and zero-root-overflow assertions. No Profile data/save/route or desktop navigation changes; C02/C06/E08. P6-03. |
|
||||
|
||||
Typography, density, controls and state presentation already have established shared owners. Minor cosmetic differences without a demonstrated usability effect stay Phase 7 reconciliation or intentional variation; no extra wrapper/refactor is scheduled. Production fonts/photos, F04 and ingress/backup/restore/schema/configuration/rollback evidence remain production gates, independent of these findings.
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# P6-03 — Accessibility and visual evidence triage
|
||||
|
||||
This is a contextual review of the current automated evidence, not a conformance certificate or a human screen-reader result. The project target remains WCAG 2.2 AA as defined in [Phase 3](../../phase-3/ACCESSIBILITY_PLAN.md). The [M01–M13 operator packet](../../phase-5/p5-15/p5-15-02/MANUAL_ACCEPTANCE.md) remains **NOT VERIFIED**; the owner's postponed reader session is not a waiver. No axe rule, assertion or result is hidden to improve acceptance.
|
||||
|
||||
## Evidence provenance and counting
|
||||
|
||||
The fresh focused Settings run (`.artifacts/phase6/current/ui/semantics.json`, started 2026-10-11 01:03:18.498 UTC) passed **4/4** browser cases with no skips, expected failures or retries. Its four detailed all-enabled axe samples have **0 violation-node occurrences** and **12 incomplete-node occurrences**: `color-contrast` 8, `aria-prohibited-attr` 2 and `aria-hidden-focus` 2. They cover EN/light at 1920×900, NB/dark at 360×900, EN/dark at 1280×900 and NB/light at 390×900. Each sample records zero application-chrome horizontal overflow.
|
||||
|
||||
The fresh company/language feedback run (`feedback.json`, started 2026-10-11 01:02:06.277 UTC) passed **4/4** native failure/retry/readback cases. Its dialogue snapshots show the translated error within the still-open company form, retained edits and reachable Save/Cancel actions. This report has no detailed axe JSON attachments, so it contributes no axe node count.
|
||||
|
||||
The first fresh ordinary browser run (`main.json`, started 2026-10-11 01:09:52.804 UTC, 30.1 minutes) completed **153 passed / 4 failed**, with no skips or retries. Its four failures are the retained named-controls tests' obsolete expectation that the company-save error remains `aria-hidden="true"`; the bounded correction now presents that error inside the active dialog. The parent retains that first failure and is running fresh corrected focused/full regressions. **This first run is partial whole-suite evidence, not a full regression pass.** Its successful audit tests provide 49 all-enabled samples and 251 retained-rule samples; they can be triaged without declaring the failed suite accepted.
|
||||
|
||||
First main source-report SHA-256: `8f513e36724e5b0c35b8d0c236b827faa21091bd59d37342eb11f723f6655d75`. This identifies the first partial run even after the parent's later report archive/rerun.
|
||||
|
||||
| First-run lane | Scans | Violation-node occurrences | Incomplete-node occurrences |
|
||||
|---|---:|---:|---:|
|
||||
| Detailed all-enabled audit, including explicitly enabled target-size | 49 | 11: landmark-unique 5; heading-order 2; aria-command-name 4 | 342: color-contrast 302; aria-prohibited-attr 28; aria-hidden-focus 9; aria-valid-attr-value 2; target-size 1 |
|
||||
| Retained-rule continuity attachments | 251 | 0 | 1,881: color-contrast 1,621; aria-prohibited-attr 201; aria-hidden-focus 37; aria-valid-attr-value 18; th-has-data-cells 4 |
|
||||
| First-run combined occurrences, distinct schemas counted once | 300 | 11 | 2,223 |
|
||||
|
||||
The missing 16 retained-rule scans are later checkpoints in the four failed tests (four per variant); the corrected full run must restore and verify those cases. The four new focused Settings cases explain 49 detailed samples compared with the previous 45. Historical Phase 5 totals (312 scans / 39 violation-node occurrences / 2,367 incomplete-node occurrences) provide provenance only. A node may recur across themes, widths and states; repeated occurrences are not independent defects. Retained-rule and all-enabled attachment schemas must be counted separately, and a partial or differently sized suite is not a like-for-like improvement measurement. Final acceptance uses the actual later completed regression report, not this first run's subset.
|
||||
|
||||
## Focused Settings incomplete checks
|
||||
|
||||
| Rule and current occurrences | Concrete target and observed context | Disposition and required acceptance |
|
||||
|---|---|---|
|
||||
| `color-contrast` — 4 | `.MuiBadge-invisible`, unread count `0`, 12px text. Axe explicitly reports short text content and cannot calculate a ratio. | Incomplete; do not turn the reported ratio `0` into a measured contrast failure or a pass. Inspect a settled visible non-zero notification badge in both themes, alongside the hidden zero state. Record actual colours/ratio and understandable unread meaning. M02/M11. |
|
||||
| `color-contrast` — 4 | Focused `#settings-tab-2` on desktop or `.MuiSelect-select` on phone. Axe says another element overlaps the background. | Incomplete. Inspect the settled selected/focused control after transitions, including keyboard focus visibility and 3:1 essential state/focus contrast. Visible text needs its applicable 4.5:1 ratio. Closing menu/backdrop sampling does not certify the control. M07/M11. |
|
||||
| `aria-prohibited-attr` — 2 | Desktop `.MuiChip-root`, `data-testid="admin-version-badge"`, a generic `div` with `aria-label="Application version e2e-verification, commit e2e1234"`. | Incomplete with a concrete semantic concern: axe identifies that this generic role does not reliably support the label. Check actual reader speech for displayed version/commit metadata and long Bokmål wrapping before selecting an appropriate semantic element or removing redundant naming. This bounded Phase 6 review did not change the shell without reader/native evidence of actual missing meaning. M01/M09. |
|
||||
| `aria-hidden-focus` — 2 | Phone `#menu-`, a closing MUI section-selector menu with `aria-hidden="true"`; its selected option still has `tabindex="0"`. | Incomplete, not waived. The check asks whether the option is tabbable **in the current state**. Exercise Tab/Shift+Tab during and after closure, Escape and restoration to the selector; verify hidden options leave keyboard/reader traversal when settled. Preserve MUI's modal isolation. M07/M09/M12. |
|
||||
|
||||
The active Notifications/Varsler panel is `#settings-panel-2`, named from `#settings-tab-2` with a translated `aria-label` fallback for the mobile selector layout. Current native role/name assertions passed at all four widths/themes/locales. Inactive tab controls reference panels 0/1/3 that remain unmounted, as before: only the active panel exists. This is distinct from a missing **active** label reference. Preserve inactive-panel and Rules-draft lifecycle ownership; verify arrow/activation and spoken selection/panel behaviour in M07 rather than remounting inactive content solely to eliminate an ID inventory warning.
|
||||
|
||||
## Sidebar child-name investigation — P6-DC05
|
||||
|
||||
Local tooling reviewed: Playwright 1.62.1, as installed in this checkout.
|
||||
|
||||
An earlier failed performance run's error-context display was noticed to contain expanded child `button` entries without quoted names, followed by their visible text. Its exact generated error-context file was overwritten when the runner reused its output directory; the first failed JSON report and log remain retained. This signal cannot retrospectively prove a missing accessible name, a transition defect or a resolved defect.
|
||||
|
||||
Current positive evidence is more specific: the focused 1920px Settings **default** `body.ariaSnapshot()` contains `button "Discover jobs"`, `button "Companies"`, `button "Compare offers"`, `button "Trash"`, `button "Profile"` and `button "Connected accounts"`; the badge contributes to `button "Reminders 2"`. The same detailed all-enabled scan has zero violations and passes `aria-command-name` for 17 nodes and `button-name` for 13. The corresponding children in `AppShell.tsx` use visible `ListItemText` for their names; top-level buttons additionally have explicit translated labels. Absence of a redundant explicit `aria-label` on text-bearing controls is not itself a naming defect.
|
||||
|
||||
The installed Playwright implementation explains why these two snapshot presentations can differ. `node_modules/playwright/lib/index.js` captures error contexts with `page.ariaSnapshot({ mode: "ai" })`. In `playwright-core/lib/coreBundle.js`, `distillAriaSnapshot` selects `aiPlugins` for that mode; its `removeRedundantNames` plugin sets a node's displayed name to an empty string when referenced child content already supplies that information. Default snapshot normalisation uses only string merging and generic-node unwrapping. Thus an unquoted AI-mode snapshot `button` with named descendant content can be deliberate output deduplication. The potential-unnamed-lines inventory is a triage heuristic, not a browser accessible-name assertion.
|
||||
|
||||
A local isolated [static-markup demonstration](evidence/snapshot-name-demonstration.json), Chromium 151.0.7922.34 / Playwright 1.62.1, reproduced this mechanism without loading the application or making network requests: Chromium CDP exposes `Discover jobs`, `Job Applications` and `Reminders 2` as the three button names, and the exact default role/name lookup finds `Discover jobs`. The default snapshot quotes all three names; AI mode omits the child-derived first/third names while preserving their paragraph/text descendants and the explicit middle label. This is tooling evidence only, not a reconstruction of the overwritten application context. The portable file records the original raw artifact path, write timestamp and SHA-256 `d590c70d4d8b7101e7facf9fa659ba2fd82c86e097526e825de9faf294318608` and retains its original payload.
|
||||
|
||||
The first fresh full run's default `cv-1440x900-en-light` snapshot also quotes all expanded child names; its name checks pass (`aria-command-name` 17, `button-name` 80 across the page). The deliberate keyboard-open EN 390px drawer sample names the children, focuses Dashboard and has zero axe violations. However, the distinct `shell-390x844-nb-dark-emulated-touch-navigation` sample has **four actual serious `aria-command-name` violation nodes**: Discover jobs, Companies, Compare offers and Trash child controls lack reader-visible text at that captured moment. Its default snapshot shows empty Job search/Career/Insights lists, and geometry still reports focus on the outside `Åpne navigasjon` launcher. This actual axe result is independent of AI snapshot formatting and remains an unresolved drawer transition/visibility/focus investigation. The sample does not establish a persistent settled name failure, and another positive sample cannot dismiss it.
|
||||
|
||||
No shell labels or navigation semantics were changed for the unconfirmed failed-context formatting signal. The mandatory next acceptance is a settled NB drawer name/AX check together with focus timing after emulated and actual touch, followed by M01/M09/M12 reader/device traversal. Capture the DOM visibility/clip state and a default/Chromium AX name at the failing instant and after transition; an actual settled failure justifies a bounded repair. Do not globally silence the name rule, weaken focus checks or assume this state passed because the enclosing collection test passed. Reader acceptance of expanded/collapsed/mobile navigation and badge speech remains mandatory.
|
||||
|
||||
## First-run remaining violation triage
|
||||
|
||||
| Rule and occurrences | Exact current context | Disposition and next work |
|
||||
|---|---|---|
|
||||
| `aria-command-name` — 4 | NB 390×844 emulated-touch drawer sample; four Jobs child controls, as detailed above. | Genuine automated serious name findings in the sampled state. Transition/visibility/focus cause is unresolved; settled native and operator checks are mandatory. No accessibility GO from the passing collection test. |
|
||||
| `heading-order` — 1 | `jobs-390x900-en-light-add-dialog-keyboard`: Add Job dialog H2, then `<h6 class="MuiTypography-subtitle2">Step 1 of 6: Add job</h6>`; its next subheading is also H6. | Confirmed retained dialog hierarchy gap affecting heading navigation. Add-job wizard/dialog migration belongs to Phase 7; retain as a required semantic correction with the wizard workflow/keyboard contracts, not a renderer/global typography rewrite. M03/M09. |
|
||||
| `heading-order` — 1 | `workspace-768x900-en-light-keyboard-section`: Match panel's Analysis/CV Match H3 sections followed by H6 Strategy snapshot. | Confirmed contextual hierarchy gap in retained existing AI strategy entry. A Phase 7 semantics correction must preserve this existing grounded action and the withheld P5-13 boundary. M05/M09; no model qualification or new review UI. |
|
||||
| `landmark-unique` — 5 | Desktop, keyboard section selector, preview end and phone portrait/landscape CV captures: `#app-main-content` is related to `<main class="page">` inside `iframe[title="CV preview page 1"]`. | Repeated moderate best-practice cross-frame finding. Parent main and separately titled preview document need actual reader navigation/distinguishability review (M06/M09). Keep white print pages, page geometry and renderer ownership; this finding authorises no pagination change. It is retained, not dismissed as compliant. |
|
||||
|
||||
## First-run broader incomplete triage
|
||||
|
||||
| Category | Concrete additional contexts | Required disposition |
|
||||
|---|---|---|
|
||||
| Prohibited ARIA labels | Generic `span[aria-label="Undo"/"Redo"]` (NB Angre/Gjør om) wrapping disabled editor actions; MUI DataGrid `span[aria-label="Sort"]`; generic desktop version Chip. | Inspect whether the actual child button/header supplies the intended name and disabled explanation, and check tooltip/reader behaviour. Remove or semantically correct only redundant wrapper naming after proving consumers retain names/help. M06/M08/M09. |
|
||||
| Unresolved contrast | Short zero badges, outlined input/tab backgrounds, overlaid modal/selector content and partially obscured table/editor text. | Retain exact targets/check reasons. Measure settled text/non-text/focus ratios and genuine disabled/hidden exceptions; do not equate `contrastRatio: 0` in an incomplete overlap calculation with a measured failure. M10/M11. |
|
||||
| Hidden focus | Modal-hidden `#root` background controls; a hidden/closing command dialog after opening Add Job; closing Settings selector menus. | Background `aria-hidden` alone is expected modal isolation, but tabbable hidden content or lost/escaped focus is not. Complete native Tab/Shift+Tab/Escape/restoration at each state and actual reader isolation. M01/M02/M05/M07/M09. |
|
||||
| Invalid attribute value | Quick Search/Hurtigsøk dialog has explicit translated `aria-label` but generated `aria-labelledby` points to absent IDs (`_r_1o_` / `_r_1q_`) in two detailed states; retained scans repeat this category. | Missing generated label references are concrete semantic debt even with an explicit name fallback. Verify actual dialog name/speech and fix the redundant invalid reference in its bounded Phase 7 dialog migration; preserve command keyboard and result-announcement contracts. M02/M09. |
|
||||
| Target size | Admin Users `data-rowindex="2"` action gridcell has overflow; axe cannot determine size and asks whether its negative-tabindex gridcell is itself a target, reporting a 4.2px spacing candidate. | Assess actual actionable buttons versus grid navigation cells, visible clipping and target/spacing at each width. The applicable 24px AA criterion and exceptions need real target measurements; do not mistake a negative-tabindex cell for a proven undersized button or declare it safe. M08/M12. |
|
||||
| Header/data associations | Four retained `th-has-data-cells` incomplete occurrences in empty/action table contexts. | Read table headers/actions/empty states using the actual data and reader table navigation. Verify a header represents real data or has a deliberately justified action column; no blanket rule disabling. M03/M04/M08/M09. |
|
||||
|
||||
## Agent visual observations — focused runs
|
||||
|
||||
These images were actually inspected with the local image viewer on 2026-10-11. They are automated synthetic-fixture captures. Observation of a visible focus ring or wrapped label does not prove its measured contrast, spoken output, physical hit area or software-keyboard behaviour. The eventual full-run manifest will separately identify the exact copied images and hashes; inspecting an earlier focused image does not mark a later image inspected automatically.
|
||||
|
||||
| Focused screenshot | Actual observation | Remaining limitation or friction |
|
||||
|---|---|---|
|
||||
| `settings-360x900-nb-dark-named-notification-panel` | The two-row shell fits the 360px capture. The Varsler selector has a visible focus outline. The notification heading, description, checkbox and explanatory text wrap inside the content surface; Save and Open Reminders remain visible. Surrounding dark chrome uses distinct surface/border boundaries. | The save action retains title-style capitalisation (`Lagre Varslingsinnstillinger`), an existing copy-style variation for Phase 7 review. Focus contrast and actual touch/reader operation remain unqualified. |
|
||||
| `settings-1920x900-en-light-named-notification-panel` | The selected Notifications tab has a clear rectangular focus outline; its white content surface is separated from the pale page. The save action is the dominant filled action and Open Reminders is outlined. Wide-screen content stays bounded rather than stretching form lines across the viewport. | Consider broader Settings migration/copy consistency only in its approved Phase 7 scope. The image cannot resolve axe's overlapped-background calculation or speak the tab/panel relationship. |
|
||||
| `company-nb-failed-save` | At phone width the translated error is directly below the dialogue title, the edited name with `æøå` remains visible, every form label fits, and Save is focused and available above Cancel. The error is persistent within the form. | The retained full-height mobile dialogue has substantial space between fields and footer. Native date input placeholders show `dd/mm/yyyy` in this English-host Chromium fixture; distinguish browser-controlled date chrome from translated application labels and test a Norwegian browser/device in M07/M12. No data-format or native-input rewrite is justified by this capture. |
|
||||
| `language-nb-failed-account-save` | The chosen `Norsk Bokmål` remains visible with a focus outline. The bottom error says the language changed on this device but failed to save to the account; `PRØV IGJEN` wraps into two readable lines at 360px. The toast fits the viewport and the General section fields wrap within their surfaces. | The snackbar overlays the lowest visible pagination content at this instant. Verify keyboard traversal/scroll and unobscured focus while it remains open, then actual speech and physical keyboard occlusion; the screenshot alone cannot close those gates. |
|
||||
|
||||
## Agent visual observations — first main capture set
|
||||
|
||||
All **14 exact copied images** in the first-run [visual manifest](evidence/visual-manifest.json) were separately opened in the local image viewer on 2026-10-11, and their file hashes were verified before setting `inspectedByAgent: true`. That manifest retains the **153 passed / 4 failed** whole-run status and source hash. These inspections concern those exact first-run files; a subsequent collector that replaces an image needs a new inspection. Human acceptance remains NOT VERIFIED.
|
||||
|
||||
| Actual copied captures | Observed design/UX result | Remaining debt or evidence limit |
|
||||
|---|---|---|
|
||||
| EN desktop and NB phone company failures | Error stays inside the labelled dialog above retained edits. EN desktop uses a two-column form with a clearly focused primary Save; NB phone fits each field and keeps Save/Cancel at the footer. | Native date chrome reflects the English-host browser; mobile full-height spacing is a retained presentation variation. Actual reader announcements, keyboard occlusion and 24px target measurements remain manual requirements. |
|
||||
| NB language failure; EN wide and NB phone Notifications | The translated device-versus-account save explanation and wrapped Retry are readable. Settings uses bounded desktop content and a named phone section selector; primary Save is distinct from the secondary destination action. | The language toast overlaps the lowest visible pagination content at this moment; verify unobscured focused content during its lifetime. Focused-ring images do not measure contrast or reader speech. |
|
||||
| Authentication at 320px | Sign-in title, credential fields, Remember me, password recovery and primary sign-in action fit inside the capture; the focused username field has a visible outline. Disabled provider actions remain readable as disabled choices. | Large rounded authentication surface is retained Phase 7 presentation, not a new Phase 6 migration. Provider integration, actual 200/400% operator tasks and disabled text contrast remain independently qualified. |
|
||||
| Jobs at 320px NB/dark; Board at 390px EN/light | Table/Board state and result count are visible. Search/filter labels wrap inside the toolbar; Jobs uses phone cards and the long synthetic company/job text wraps. Board shows a whole first-column card and a glimpse of the next column, reinforcing its horizontal workspace. | Only the currently visible content is inspected; lower card actions still require scrolling/native workflows. Board column scrolling is legitimate two-dimensional content, not evidence of application-chrome overflow. Physical drag and software keyboard remain open. |
|
||||
| Dashboard 1440px EN/light | Page purpose, onboarding progress, four labelled metrics and their population/time captions have distinct hierarchy. Today and pipeline surfaces begin below the metrics; contextual actions remain visible. | Onboarding occupies substantial vertical space while incomplete, consistent with its purpose. The image does not certify dashboard timing/reliability, source correctness or future Phase 8 drag/resize. |
|
||||
| Analytics 390px EN/light | Period/population explanation wraps; selected six-month control is distinct and the 24-month alternative wraps onto a second line. Activity report labels its date range, recorded-response fraction, line styles and exact-values continuation. | Only one chart is visible. Chart values/provenance are verified by fixtures/native tests separately; charts' exact-values disclosure, focus and non-colour meaning require reader/keyboard checks. |
|
||||
| Job workspace 320px EN/light | Long title/company wrap; status and edit action stay visible. Progress and section tabs scroll within their own area; selected Timeline and Activity History are visible with a focus outline. | At the shown scroll position the previous Application tab is partly off the left edge. This is a tab-strip scroll state, not hidden evidence of a removed section; verify every tab can be deliberately revealed/reached, including spoken state. |
|
||||
| Career Profile 390px NB/dark | Profile/import surfaces fit, revised avatar initials are dark against the existing pale primary surface, long synthetic account identity wraps and source-workspace content remains visible. | This **first-run baseline** shows the floating `Område i karrierearbeidsområdet` selector label clipped at the top of its rounded navigation surface. It triggered the bounded P6-03 correction below; its later native RED/GREEN and separately inspected before/after images confirm the repair. The original baseline image remains retained and is not relabelled as repaired. |
|
||||
| CV 1440px EN/light; mobile physical-preview capture | Desktop editor and preview remain separate, with source-versus-CV guidance prominent. White print page is bounded by preview chrome. Phone Edit/Preview controls and PDF action fit; Preview has a visible focus ring and the page is fit to width with an explicit percentage and page count. | Small document text at fit-width is expected print-canvas scaling; zoom/document access and actual reader traversal remain necessary. Editable long CV name scroll/clipping is distinct from route-chrome reflow. These images do not qualify production fonts/photos or paginate by appearance; physical measurements/fidelity proofs remain authoritative. |
|
||||
|
||||
## Bounded P6-03 mobile Career label repair — verified native RED/GREEN
|
||||
|
||||
The first-run image and two new native cases confirmed a real clipped field label, so this bounded correction was completed in Phase 6. `CareerProfilePage.tsx` changes only the mobile FormControl from padding `1.25` to margin `1.25` with automatic width, and removes the InputLabel's duplicate left margin. That moves the absolute floating label inside the existing clipped Paper while keeping the Select's usable inset. Paper overflow, desktop tabs, label/Select association, section handlers, default routes and profile/CV save ownership remain unchanged. No translation, framework or renderer changes accompany it.
|
||||
|
||||
The separately retained [label proof](evidence/career-selector-label-proof.json) records three actual runs, report hashes, exact geometry and four before/after image hashes. It does not overwrite the first 14-image baseline manifest:
|
||||
|
||||
| Native run | Actual result | Meaning |
|
||||
|---|---|---|
|
||||
| RED, 2026-10-11 08:38:01.973 UTC | **0 passed / 2 failed**, no skips/retries. Both NB/dark 320px and EN/light 390px report `labelTop=200` versus clipping `navTop=208`. | Ordinary assertions first reproduce 8px of vertical clipping. Initial test did not attach all remaining bounds; the proof retains only its actually reported values. |
|
||||
| First post-CSS attempt, 08:42:52.719 UTC | Both label geometry checks pass (`210 ≥ 208`, bottom `225.09375 ≤ 272`), then **2 tests fail** because a newly written ancillary assertion incorrectly expects `section=overview`. | Existing approved navigation removes the default query and reaches `/career`. Parent corrected the test to the exact existing URL and selected Overview text; no route-handler change and no masked failure. This failed attempt is retained. |
|
||||
| Final focused GREEN, 08:44:30.468 UTC | **2/2 passed**, no skips/retries, 39.4 seconds. Both variants retain `labelTop=210`, `labelBottom=225.09375`, `navTop=208`, `navBottom=272`; application-chrome overflow is 0px. Keyboard selection reaches `/career` with Overview selected. | Finite native proof of the specific label repair and preserved existing selector/default-route behaviour. The parent final whole-suite regression remains independently required. |
|
||||
|
||||
All four exact RED/GREEN screenshots were opened with the local image viewer and hash-verified before marking inspection. The original RED images visibly crop the upper part of the floating label; the GREEN images show the entire EN `Career workspace section` and NB `Område i karrierearbeidsområdet` label above the Select outline inside the same surface. Surrounding profile/import controls retain their layout and translated names. This closes the specific automated/agent-visual clipping finding; it does not close human reader, touch, zoom/forced-colour or production font/photo acceptance.
|
||||
|
||||
## Remaining operator dependencies
|
||||
|
||||
| Area | Current evidence and limit | Still required |
|
||||
|---|---|---|
|
||||
| Landmarks, headings, names and reading order | Native/DOM assertions can verify exact current relationships. They do not prove speech, browse-mode order or understanding. | M01–M09 with actual NVDA/Narrator/browser versions and exact observed speech; names, validation/help relationships, live announcements and restored focus. |
|
||||
| Modal/transition focus | Axe hidden-focus or overlapping-background results require state-specific triage. A static early snapshot cannot decide settled focus. | Opening, nesting, Escape, Tab/Shift+Tab and trigger restoration, including the mobile drawer and selector. M01/M02/M05–M09. |
|
||||
| CV editor/preview | White document pages and separately named preview documents preserve print output. A parent/iframe landmark warning is not permission to alter pagination geometry. | M06/M09 actual reader traversal between editor and preview, source/override distinction, section order, Save/Discard and long-document access; retain fidelity proofs separately. |
|
||||
| Reflow, zoom and visibility | Finite browser widths, browser-engine zoom and text-spacing assertions support only their recorded Chromium cases. | M10 actual task execution, text-only zoom and supported other browsers; M11 forced colours, contrast and reduced motion; focus not obscured by sticky chrome. |
|
||||
| Physical touch and mobile AT | Emulated phone geometry/pointer input and screenshots cannot qualify real keyboards, gestures, drag or touch targets. | M12 physical portrait/landscape/software keyboard and actual VoiceOver/TalkBack; 24px AA criterion/spacing exceptions and 44px touch aim recorded separately. |
|
||||
| Production font/photo output | Local synthetic fixtures cannot establish production Linux font availability or real photo rendering. | Existing production font/photo qualification and F04/release gates. Production remains NO-GO. |
|
||||
| Withheld AI capability | No qualification or AI review activation is included in these scans. | M13 applies only after P5-13's independent model/grounding/human qualification; its UI remains deferred. |
|
||||
|
||||
Automated and agent visual observations will be recorded separately from operator acceptance. No PRES group is promoted to PASS by this triage alone, and no manual field is filled from an expected result, axe status or screenshot.
|
||||
@@ -0,0 +1,25 @@
|
||||
# P6-03 — Responsive, accessibility and localisation
|
||||
|
||||
Baseline: [P6-00 register](../p6-00/FINDINGS.md), actual Phase 5 final 312 axe scans / 39 all-enabled violation-node occurrences / 2,367 incomplete occurrences. Those are historical repeated nodes, not independent defects or compliance certification. Current source is the bounded P6-01/P6-02 correction set plus the P6-03 Career selector label repair; final integrated native evidence is recorded separately in [P6-05](../p6-05/README.md).
|
||||
|
||||
## Scope and preservation
|
||||
|
||||
Retain the established [accessibility standard and manual gates](../../phase-3/ACCESSIBILITY_PLAN.md), MUI keyboard/focus architecture, approved breakpoints/density and physical CV renderer. Review EN/Bokmål and light/dark at 320, 360, 390, 768, 1024, 1280, 1440 and 1920 CSS pixels, with intermediate breakpoint transitions and portrait/landscape. Existing tests cover 100/200/400% Chromium zoom and text-spacing overrides separately from normal viewport resizing. Two-dimensional Board/document canvas scrolling is considered separately from application-chrome overflow.
|
||||
|
||||
Semantic Login/Career/Account/CV/Admin heading fixes preserve their visual styles. Avatar initials use the existing contrasting theme pair. Settings desktop tabs now own named panel IDs; the translated name remains available when a phone uses the existing section selector. Rules drafts, inactive-panel unmounting, saves/discard and focus architecture are preserved. Company list/card dates now use the same UI locale as the existing relationship dialog; both EN and NB tests first reproduced host-locale dates. Jobs' two pending selected-company labels reuse `jobTableCompany` instead of hard-coded English. New language-save feedback is translated and bounded to the latest choice/request, without changing server write semantics.
|
||||
|
||||
## Native evidence and triage
|
||||
|
||||
The retained first full attempt completed153/157 with four obsolete hidden-company-error assertions. Its49 detailed all-enabled scans and251 retained-rule scans are **pre-Career-spacing-repair baseline**, not the final integrated PASS. [AXE_TRIAGE](AXE_TRIAGE.md) records11 repeated violation nodes and2,223 incomplete occurrences across300 scans, every rule category/context and fourteen actually inspected screenshots. Final full results are separate in P6-05; partial-scope evidence is not promoted to whole-suite acceptance.
|
||||
|
||||
P6-DC16 is a confirmed bounded mobile label defect. Native geometry RED in NB320/dark and EN390/light proves the floating label8px above the clipping container. The repair changes only the existing mobile FormControl from padding to margin with automatic inner width and removes the redundant label offset. The [separate RED/intermediate/GREEN proof](evidence/career-selector-label-proof.json) records **2/2 final focused cases passed**, both labels at210–225.09375px inside the208–272px navigation surface, zero application-chrome overflow and keyboard selection of the unchanged `/career` Overview default. Its four hashed before/after images were actually inspected; the initial fourteen images remain attributed baseline. The intermediate post-CSS geometry pass followed by an incorrect test-only URL expectation is retained explicitly. This is a completed bounded Phase6 repair, not a full Career migration.
|
||||
|
||||
Fresh post-CSS [checkpoint validation](evidence/checkpoint-validation.json) records **521 frontend tests /85 suites**, application/browser TypeScript, lint and production build `2LDblja_XnSBWSuY6ys_V` passing. The combined Settings/Career selector run passes **6/6** with no skips, retries or flaky results at2026-10-11 08:45:10.463 UTC: four named Settings variants plus the same two label cases. These six cases are a combined rerun, not eight distinct tests added to the full suite. Exact commands/report hashes are retained in the checkpoint validation and [semantics result manifest](../p6-05/evidence/semantics-results.json). This checkpoint's bounded corrections are complete with manual/axe qualifications retained; the fresh159-case full integrated run remains separately pending in P6-05 until its actual outcome is verified.
|
||||
|
||||
The fresh ordinary browser run includes the existing thirteen-area audit, real zoom audit, keyboard dialog/command/back/focus/file-picker/CV preview/save workflows and four new named-Settings-panel/reflow cases (EN light1920, NB dark360, EN dark1280, NB light390). Company and language errors/retries use intercepted failures followed by real native persistence/readback. All-enabled axe results, incomplete rules and sample-specific targets are retained in `evidence/axe-summary.json`; representative screenshots have source test/state/viewport and hashes in `evidence/visual-manifest.json`.
|
||||
|
||||
Every incomplete category is retained for contextual review: contrast may involve disabled/overlaid/cross-frame content; prohibited/invalid ARIA attributes need actual MUI/hidden/settled contexts; hidden focus needs transition/open/closed focus behavior; target-size and table-cell relationships need actual active controls/data. No rule is removed or disabled to improve counts. Existing retained-rule scans are historical continuity evidence; current all-enabled scans provide broader triage. Remaining preview main/landmark findings span the parent and separately named iframe document; a best-practice cross-frame finding does not authorize changing A4 geometry. Settled drawer names/focus must be assessed from actual native AX snapshots, not inferred from text or an early transition sample.
|
||||
|
||||
Automated names, controls, dynamic status, input error and focus assertions do not replace spoken screen-reader evaluation. The [M01–M13 operator packet](../../phase-5/p5-15/p5-15-02/MANUAL_ACCEPTANCE.md) remains **NOT VERIFIED** for actual reader/version/operator/device/spoken results. Physical touch/native dragging/software keyboard/mobile AT, text-only zoom/forced colours and supported alternate browsers retain their exact manual requirements. Production Linux font/photo qualification also remains open.
|
||||
|
||||
Relevant PRES: E02/E06/E07/E08, J05/J07/J08, W01/W08, C06–C12, S01/S03/S04. No group is promoted to full acceptance solely by finite browser or axe evidence. No route, canonical fact, CV override, frozen document, authorisation, pagination geometry or model qualification changes. Completion/push and conditional acceptance are in the chronological log and final report.
|
||||
@@ -0,0 +1,292 @@
|
||||
{
|
||||
"scope": "Bounded P6-03 Career mobile selector floating-label correction only; no human/device acceptance",
|
||||
"sourceChange": "CareerProfilePage mobile FormControl padding changed to margin with automatic width; redundant InputLabel left margin removed. Paper clipping, desktop Tabs, handlers and route/save ownership unchanged.",
|
||||
"red": {
|
||||
"sourceReport": ".artifacts/phase6/current/ui/attempts/label-084252/label.json",
|
||||
"sourceReportSha256": "2494352d49407649937dfc0485a601a7f909d9421305705de8ad5f986e055a44",
|
||||
"stats": {
|
||||
"startTime": "2026-10-11T08:38:01.973Z",
|
||||
"duration": 37396.102,
|
||||
"expected": 0,
|
||||
"skipped": 0,
|
||||
"unexpected": 2,
|
||||
"flaky": 0
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"test": "[P6-03] nb/dark Career selector floating label is not clipped at 320px",
|
||||
"status": "failed",
|
||||
"retry": 0,
|
||||
"errors": [
|
||||
"Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 208\nReceived: 200\n\n 174 | const label = navigation.locator('#career-workspace-section-label');\n 175 | const bounds = await label.evaluate(element => { const label = element.getBoundingClientRect(); const nav = element.closest('nav')!.getBoundingClientRect(); return { labelTop: label.top, labelBottom: label.bottom, navTop: nav.top, navBottom: nav.bottom }; });\n> 176 | expect(bounds.labelTop).toBeGreaterThanOrEqual(bounds.navTop);\n | ^\n 177 | expect(bounds.labelBottom).toBeLessThanOrEqual(bounds.navBottom);\n 178 | const evidence = await collect(page, info, sample, 'career-selector-label');\n 179 | expect(evidence.geometry.pageHorizontalOverflow).toBe(0);\n at E:\\Storage\\Projects\\Active\\Job tracker\\job-tracker-ui\\e2e\\responsive-accessibility-audit.spec.ts:176:29"
|
||||
],
|
||||
"screenshot": {
|
||||
"file": "screenshots/career-selector-label-red-320-nb.png",
|
||||
"sha256": "ad5ad411a65dcdad687c15226143b4a657a7c87b0fe3b121bad0e8a79c4746b0",
|
||||
"sourceAttachment": "screenshot",
|
||||
"actualSourceFile": ".artifacts/phase6/current/ui/attempts/label-084252/label-results/responsive-accessibility-a-63ce6-bel-is-not-clipped-at-320px-chromium/test-failed-1.png",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
"knownBoundsFromFailingAssertion": {
|
||||
"labelTop": 200,
|
||||
"navTop": 208,
|
||||
"otherBounds": "Not attached in this initial RED test; do not infer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"test": "[P6-03] en/light Career selector floating label is not clipped at 390px",
|
||||
"status": "failed",
|
||||
"retry": 0,
|
||||
"errors": [
|
||||
"Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 208\nReceived: 200\n\n 174 | const label = navigation.locator('#career-workspace-section-label');\n 175 | const bounds = await label.evaluate(element => { const label = element.getBoundingClientRect(); const nav = element.closest('nav')!.getBoundingClientRect(); return { labelTop: label.top, labelBottom: label.bottom, navTop: nav.top, navBottom: nav.bottom }; });\n> 176 | expect(bounds.labelTop).toBeGreaterThanOrEqual(bounds.navTop);\n | ^\n 177 | expect(bounds.labelBottom).toBeLessThanOrEqual(bounds.navBottom);\n 178 | const evidence = await collect(page, info, sample, 'career-selector-label');\n 179 | expect(evidence.geometry.pageHorizontalOverflow).toBe(0);\n at E:\\Storage\\Projects\\Active\\Job tracker\\job-tracker-ui\\e2e\\responsive-accessibility-audit.spec.ts:176:29"
|
||||
],
|
||||
"screenshot": {
|
||||
"file": "screenshots/career-selector-label-red-390-en.png",
|
||||
"sha256": "379303b21c316ed189b3550fd882b42ecdbd9d9f64064af1794bee5480e9547d",
|
||||
"sourceAttachment": "screenshot",
|
||||
"actualSourceFile": ".artifacts/phase6/current/ui/attempts/label-084252/label-results/responsive-accessibility-a-6de9e-bel-is-not-clipped-at-390px-chromium/test-failed-1.png",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
"knownBoundsFromFailingAssertion": {
|
||||
"labelTop": 200,
|
||||
"navTop": 208,
|
||||
"otherBounds": "Not attached in this initial RED test; do not infer"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"intermediate": {
|
||||
"sourceReport": ".artifacts/phase6/current/ui/attempts/label-084429/label.json",
|
||||
"sourceReportSha256": "5b32940f1f62c9ab0d513327e4a59fceffce5d1ec8f61794416db650e7ff08bf",
|
||||
"stats": {
|
||||
"startTime": "2026-10-11T08:42:52.719Z",
|
||||
"duration": 50984.018,
|
||||
"expected": 0,
|
||||
"skipped": 0,
|
||||
"unexpected": 2,
|
||||
"flaky": 0
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"test": "[P6-03] nb/dark Career selector floating label is not clipped at 320px",
|
||||
"status": "failed",
|
||||
"retry": 0,
|
||||
"errors": [
|
||||
"Error: expect(page).toHaveURL(expected) failed\n\nExpected pattern: /section=overview/\nReceived string: \"http://localhost:3300/career\"\nTimeout: 5000ms\n\nCall log:\n - Expect \"toHaveURL\" with timeout 5000ms\n 14 × locator resolved to <html lang=\"nb-NO\" data-color-scheme=\"dark\">…</html>\n - unexpected value \"http://localhost:3300/career\"\n\n\n 181 | await navigation.getByRole('combobox').press('Enter');\n 182 | await page.getByRole('option', { name: translations[language].careerWorkspaceOverviewTab, exact: true }).press('Enter');\n> 183 | await expect(page).toHaveURL(/section=overview/);\n | ^\n 184 | });\n 185 | }\n 186 |\n at E:\\Storage\\Projects\\Active\\Job tracker\\job-tracker-ui\\e2e\\responsive-accessibility-audit.spec.ts:183:24"
|
||||
],
|
||||
"nativeGeometry": {
|
||||
"sample": {
|
||||
"area": "profile",
|
||||
"path": "/career?section=profile",
|
||||
"width": 320,
|
||||
"language": "nb",
|
||||
"theme": "dark"
|
||||
},
|
||||
"bounds": {
|
||||
"labelTop": 210,
|
||||
"labelBottom": 225.09375,
|
||||
"navTop": 208,
|
||||
"navBottom": 272
|
||||
},
|
||||
"proofKind": "Native CSS label bounds versus clipping navigation container; no human/device acceptance"
|
||||
},
|
||||
"nativeAudit": {
|
||||
"state": "profile-320x900-nb-dark-career-selector-label",
|
||||
"sample": {
|
||||
"area": "profile",
|
||||
"path": "/career?section=profile",
|
||||
"width": 320,
|
||||
"language": "nb",
|
||||
"theme": "dark"
|
||||
},
|
||||
"viewport": {
|
||||
"width": 320,
|
||||
"height": 900,
|
||||
"devicePixelRatio": 1
|
||||
},
|
||||
"appChromeHorizontalOverflowCssPx": 0,
|
||||
"axeViolations": [],
|
||||
"axeIncompleteRules": [
|
||||
{
|
||||
"id": "color-contrast",
|
||||
"nodes": 44
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"test": "[P6-03] en/light Career selector floating label is not clipped at 390px",
|
||||
"status": "failed",
|
||||
"retry": 0,
|
||||
"errors": [
|
||||
"Error: expect(page).toHaveURL(expected) failed\n\nExpected pattern: /section=overview/\nReceived string: \"http://localhost:3300/career\"\nTimeout: 5000ms\n\nCall log:\n - Expect \"toHaveURL\" with timeout 5000ms\n 14 × locator resolved to <html lang=\"en\" data-color-scheme=\"light\">…</html>\n - unexpected value \"http://localhost:3300/career\"\n\n\n 181 | await navigation.getByRole('combobox').press('Enter');\n 182 | await page.getByRole('option', { name: translations[language].careerWorkspaceOverviewTab, exact: true }).press('Enter');\n> 183 | await expect(page).toHaveURL(/section=overview/);\n | ^\n 184 | });\n 185 | }\n 186 |\n at E:\\Storage\\Projects\\Active\\Job tracker\\job-tracker-ui\\e2e\\responsive-accessibility-audit.spec.ts:183:24"
|
||||
],
|
||||
"nativeGeometry": {
|
||||
"sample": {
|
||||
"area": "profile",
|
||||
"path": "/career?section=profile",
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"theme": "light"
|
||||
},
|
||||
"bounds": {
|
||||
"labelTop": 210,
|
||||
"labelBottom": 225.09375,
|
||||
"navTop": 208,
|
||||
"navBottom": 272
|
||||
},
|
||||
"proofKind": "Native CSS label bounds versus clipping navigation container; no human/device acceptance"
|
||||
},
|
||||
"nativeAudit": {
|
||||
"state": "profile-390x900-en-light-career-selector-label",
|
||||
"sample": {
|
||||
"area": "profile",
|
||||
"path": "/career?section=profile",
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"theme": "light"
|
||||
},
|
||||
"viewport": {
|
||||
"width": 390,
|
||||
"height": 900,
|
||||
"devicePixelRatio": 1
|
||||
},
|
||||
"appChromeHorizontalOverflowCssPx": 0,
|
||||
"axeViolations": [],
|
||||
"axeIncompleteRules": [
|
||||
{
|
||||
"id": "color-contrast",
|
||||
"nodes": 44
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"green": {
|
||||
"sourceReport": ".artifacts/phase6/current/ui/label.json",
|
||||
"sourceReportSha256": "81b73323d902b63812d36228deae29a559767f209ce4a0f4885632d6e644b84a",
|
||||
"stats": {
|
||||
"startTime": "2026-10-11T08:44:30.468Z",
|
||||
"duration": 39406.638,
|
||||
"expected": 2,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"test": "[P6-03] nb/dark Career selector floating label is not clipped at 320px",
|
||||
"status": "passed",
|
||||
"retry": 0,
|
||||
"errors": [],
|
||||
"nativeGeometry": {
|
||||
"sample": {
|
||||
"area": "profile",
|
||||
"path": "/career?section=profile",
|
||||
"width": 320,
|
||||
"language": "nb",
|
||||
"theme": "dark"
|
||||
},
|
||||
"bounds": {
|
||||
"labelTop": 210,
|
||||
"labelBottom": 225.09375,
|
||||
"navTop": 208,
|
||||
"navBottom": 272
|
||||
},
|
||||
"proofKind": "Native CSS label bounds versus clipping navigation container; no human/device acceptance"
|
||||
},
|
||||
"screenshot": {
|
||||
"file": "screenshots/career-selector-label-green-320-nb.png",
|
||||
"sha256": "ccf5b6d77f7804f76bee27a22de3b13d7b82844e45adfbd731a0c52ea53f0beb",
|
||||
"sourceAttachment": "profile-320x900-nb-dark-career-selector-label",
|
||||
"actualSourceFile": "E:/Storage/Projects/Active/Job tracker/.artifacts/phase6/current/ui/label-results/responsive-accessibility-a-63ce6-bel-is-not-clipped-at-320px-chromium/attachments/profile-320x900-nb-dark-career-selector-label-ba52293a03288bc846e536f35fb021b4f7ef3bfd.png",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
"nativeAudit": {
|
||||
"state": "profile-320x900-nb-dark-career-selector-label",
|
||||
"sample": {
|
||||
"area": "profile",
|
||||
"path": "/career?section=profile",
|
||||
"width": 320,
|
||||
"language": "nb",
|
||||
"theme": "dark"
|
||||
},
|
||||
"viewport": {
|
||||
"width": 320,
|
||||
"height": 900,
|
||||
"devicePixelRatio": 1
|
||||
},
|
||||
"appChromeHorizontalOverflowCssPx": 0,
|
||||
"axeViolations": [],
|
||||
"axeIncompleteRules": [
|
||||
{
|
||||
"id": "color-contrast",
|
||||
"nodes": 44
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"test": "[P6-03] en/light Career selector floating label is not clipped at 390px",
|
||||
"status": "passed",
|
||||
"retry": 0,
|
||||
"errors": [],
|
||||
"nativeGeometry": {
|
||||
"sample": {
|
||||
"area": "profile",
|
||||
"path": "/career?section=profile",
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"theme": "light"
|
||||
},
|
||||
"bounds": {
|
||||
"labelTop": 210,
|
||||
"labelBottom": 225.09375,
|
||||
"navTop": 208,
|
||||
"navBottom": 272
|
||||
},
|
||||
"proofKind": "Native CSS label bounds versus clipping navigation container; no human/device acceptance"
|
||||
},
|
||||
"screenshot": {
|
||||
"file": "screenshots/career-selector-label-green-390-en.png",
|
||||
"sha256": "61d0ec1f9f06b9c7e8a242b73423a45d527c4c8e7e4758fccf4f3871e4616d6f",
|
||||
"sourceAttachment": "profile-390x900-en-light-career-selector-label",
|
||||
"actualSourceFile": "E:/Storage/Projects/Active/Job tracker/.artifacts/phase6/current/ui/label-results/responsive-accessibility-a-6de9e-bel-is-not-clipped-at-390px-chromium/attachments/profile-390x900-en-light-career-selector-label-3a0428f98c934f9a73e0f3b9b3ca53026980edf7.png",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
"nativeAudit": {
|
||||
"state": "profile-390x900-en-light-career-selector-label",
|
||||
"sample": {
|
||||
"area": "profile",
|
||||
"path": "/career?section=profile",
|
||||
"width": 390,
|
||||
"language": "en",
|
||||
"theme": "light"
|
||||
},
|
||||
"viewport": {
|
||||
"width": 390,
|
||||
"height": 900,
|
||||
"devicePixelRatio": 1
|
||||
},
|
||||
"appChromeHorizontalOverflowCssPx": 0,
|
||||
"axeViolations": [],
|
||||
"axeIncompleteRules": [
|
||||
{
|
||||
"id": "color-contrast",
|
||||
"nodes": 44
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"intermediateDisposition": "After CSS correction both geometry checks passed; test then wrongly expected section=overview. Existing approved handler removes the default query and navigates to /career. Parent corrected the test to the exact existing URL plus the selected Overview label; no application route change.",
|
||||
"greenChecks": [
|
||||
"Native floating label fully bounded by clipping navigation Paper",
|
||||
"Zero app-chrome horizontal overflow at 320 NB/dark and 390 EN/light",
|
||||
"Keyboard section selection reaches existing /career default URL and selected Overview text"
|
||||
],
|
||||
"humanAcceptance": "NOT VERIFIED; no screen-reader speech, physical device, software keyboard or production font/photo qualification",
|
||||
"wholeSuiteAcceptance": "This focused GREEN2/2 is separate from the first main153/157 and does not replace the parent final full regression"
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
{
|
||||
"scope": "P6-03 bounded checkpoint; final integrated acceptance recorded separately in P6-05",
|
||||
"lanes": {
|
||||
"jest": {
|
||||
"command": {
|
||||
"name": "jest",
|
||||
"command": [
|
||||
"rtk",
|
||||
"proxy",
|
||||
"npm.cmd",
|
||||
"test",
|
||||
"--",
|
||||
"--runInBand",
|
||||
"--watchAll=false",
|
||||
"--json",
|
||||
"--outputFile=E:\\Storage\\Projects\\Active\\Job tracker\\.artifacts\\phase6\\current\\ui\\jest.json"
|
||||
],
|
||||
"startedUtc": "2026-10-11T08:39:27.752795+00:00",
|
||||
"finishedUtc": "2026-10-11T08:42:14.567530+00:00",
|
||||
"exitCode": 0
|
||||
},
|
||||
"logSha256": "a9123195009fc6c92e0c73ee36aa4a35a2c2744916c5229723d8c01dbdbaf2c3",
|
||||
"passed": 521,
|
||||
"suites": 85,
|
||||
"skipped": 0
|
||||
},
|
||||
"typecheck": {
|
||||
"command": {
|
||||
"name": "typecheck",
|
||||
"command": [
|
||||
"rtk",
|
||||
"proxy",
|
||||
"npm.cmd",
|
||||
"run",
|
||||
"typecheck"
|
||||
],
|
||||
"startedUtc": "2026-10-11T08:42:14.569044+00:00",
|
||||
"finishedUtc": "2026-10-11T08:42:23.797213+00:00",
|
||||
"exitCode": 0
|
||||
},
|
||||
"logSha256": "89b0ec97b537eca6560c13ca2dfea9e3a97dd1bb35580c4ff39d2462db25e080"
|
||||
},
|
||||
"browser-typecheck": {
|
||||
"command": {
|
||||
"name": "browser-typecheck",
|
||||
"command": [
|
||||
"rtk",
|
||||
"proxy",
|
||||
"npm.cmd",
|
||||
"exec",
|
||||
"tsc",
|
||||
"--",
|
||||
"--project",
|
||||
"../.artifacts/p5-15-01/e2e-tsconfig.json",
|
||||
"--noEmit"
|
||||
],
|
||||
"startedUtc": "2026-10-11T08:44:26.535163+00:00",
|
||||
"finishedUtc": "2026-10-11T08:44:29.966649+00:00",
|
||||
"exitCode": 0
|
||||
},
|
||||
"logSha256": "d2993bc68ad9a63f711c8f5473155e2ba00fdcd461220cc3849185f2f9ad93e6"
|
||||
},
|
||||
"lint": {
|
||||
"command": {
|
||||
"name": "lint",
|
||||
"command": [
|
||||
"rtk",
|
||||
"proxy",
|
||||
"npm.cmd",
|
||||
"run",
|
||||
"lint"
|
||||
],
|
||||
"startedUtc": "2026-10-11T08:42:27.286365+00:00",
|
||||
"finishedUtc": "2026-10-11T08:42:44.756991+00:00",
|
||||
"exitCode": 0
|
||||
},
|
||||
"logSha256": "b040dbeca9b4adb3f6f4c25ac49de0d37e921375b2d9b57e87b542a10f599913"
|
||||
},
|
||||
"build": {
|
||||
"command": {
|
||||
"name": "build",
|
||||
"command": [
|
||||
"rtk",
|
||||
"proxy",
|
||||
"npm.cmd",
|
||||
"run",
|
||||
"build"
|
||||
],
|
||||
"startedUtc": "2026-10-11T08:42:44.758981+00:00",
|
||||
"finishedUtc": "2026-10-11T08:42:52.176965+00:00",
|
||||
"exitCode": 0
|
||||
},
|
||||
"logSha256": "7071afb6db88d72ceb04199f386c107756e94f2916f0bc51a20ce6523f7e897e"
|
||||
},
|
||||
"label": {
|
||||
"command": {
|
||||
"name": "label",
|
||||
"command": [
|
||||
"rtk",
|
||||
"proxy",
|
||||
"node",
|
||||
"node_modules/@playwright/test/cli.js",
|
||||
"test",
|
||||
"e2e/responsive-accessibility-audit.spec.ts",
|
||||
"--grep",
|
||||
"Career selector floating label",
|
||||
"--retries=0",
|
||||
"--reporter=list,json",
|
||||
"--output=E:\\Storage\\Projects\\Active\\Job tracker\\.artifacts\\phase6\\current\\ui\\label-results"
|
||||
],
|
||||
"startedUtc": "2026-10-11T08:44:29.971158+00:00",
|
||||
"finishedUtc": "2026-10-11T08:45:09.907678+00:00",
|
||||
"exitCode": 0,
|
||||
"stats": {
|
||||
"startTime": "2026-10-11T08:44:30.468Z",
|
||||
"duration": 39406.638,
|
||||
"expected": 2,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
}
|
||||
},
|
||||
"logSha256": "54e17aba61643bc105390f57a2edf838360643a8d9e24578f06c5bac884b04af",
|
||||
"stats": {
|
||||
"startTime": "2026-10-11T08:44:30.468Z",
|
||||
"duration": 39406.638,
|
||||
"expected": 2,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
}
|
||||
},
|
||||
"semantics": {
|
||||
"command": {
|
||||
"name": "semantics",
|
||||
"command": [
|
||||
"rtk",
|
||||
"proxy",
|
||||
"node",
|
||||
"node_modules/@playwright/test/cli.js",
|
||||
"test",
|
||||
"e2e/responsive-accessibility-audit.spec.ts",
|
||||
"--grep",
|
||||
"P6-03",
|
||||
"--retries=0",
|
||||
"--reporter=list,json",
|
||||
"--output=E:\\Storage\\Projects\\Active\\Job tracker\\.artifacts\\phase6\\current\\ui\\semantics-results"
|
||||
],
|
||||
"startedUtc": "2026-10-11T08:45:09.916201+00:00",
|
||||
"finishedUtc": "2026-10-11T08:46:49.640163+00:00",
|
||||
"exitCode": 0,
|
||||
"stats": {
|
||||
"startTime": "2026-10-11T08:45:10.463Z",
|
||||
"duration": 99144.70899999999,
|
||||
"expected": 6,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
}
|
||||
},
|
||||
"logSha256": "fa961d9d2c01fb10770f4b1e431fef9abc13ea94d7a76567c1766aeec67573a6",
|
||||
"stats": {
|
||||
"startTime": "2026-10-11T08:45:10.463Z",
|
||||
"duration": 99144.70899999999,
|
||||
"expected": 6,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"manual": "M01-M13, physical touch/software keyboard and production fonts/photos NOT VERIFIED",
|
||||
"applicationSourceSha256": "e96364a9851aee1866454e25ae3da6e29607d2678b03201797fc8412c3f4138e",
|
||||
"buildId": "2LDblja_XnSBWSuY6ys_V"
|
||||
}
|
||||
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 43 KiB |
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"sourceArtifact": ".artifacts/phase6/current/design/snapshot-name-demonstration.json",
|
||||
"sourceArtifactSha256": "d590c70d4d8b7101e7facf9fa659ba2fd82c86e097526e825de9faf294318608",
|
||||
"provenance": "Worker executed installed Playwright on isolated local static markup with all network routes aborted; no application request or mutation, no human reader result. Original JSON payload is retained unchanged below.",
|
||||
"sourceArtifactWrittenUtc": "2026-10-11T01:20:12.872548+00:00",
|
||||
"demonstration": {
|
||||
"evidenceKind": "Local tooling demonstration on isolated static markup; not application acceptance",
|
||||
"browser": "151.0.7922.34",
|
||||
"playwright": "1.62.1",
|
||||
"defaultSnapshot": "- button \"Discover jobs\":\n - paragraph: Discover jobs\n- button \"Job Applications\":\n - paragraph: Job Applications\n- button \"Reminders 2\":\n - paragraph: Reminders\n - text: \"2\"",
|
||||
"aiSnapshot": "- generic [active] [ref=e1]:\n - button [ref=e2]:\n - paragraph [ref=e3]: Discover jobs\n - button \"Job Applications\" [ref=e4]:\n - paragraph [ref=e5]: Job Applications\n - button [ref=e6]:\n - paragraph [ref=e7]: Reminders\n - text: \"2\"",
|
||||
"nativeButtonNames": [
|
||||
"Discover jobs",
|
||||
"Job Applications",
|
||||
"Reminders 2"
|
||||
],
|
||||
"exactDefaultRoleNameCount": 1,
|
||||
"limitation": "Demonstrates snapshot formatting only; does not retrospectively recreate the overwritten failed application context or qualify reader operation"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"sourceReportSha256": "8f513e36724e5b0c35b8d0c236b827faa21091bd59d37342eb11f723f6655d75",
|
||||
"wholeRunStats": {
|
||||
"startTime": "2026-10-11T01:09:52.804Z",
|
||||
"duration": 1805256.29,
|
||||
"expected": 153,
|
||||
"skipped": 0,
|
||||
"unexpected": 4,
|
||||
"flaky": 0
|
||||
},
|
||||
"screenshots": [
|
||||
{
|
||||
"test": "[P6-02] en company save failure stays in the dialog and retry persists the retained draft",
|
||||
"state": "company-en-failed-save",
|
||||
"file": "screenshots/company-en-failed-save.png",
|
||||
"sha256": "35afbd5eda558f20499a53a7b9744600fca3c22323f7ef93d0f6b5ed9498541d",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P6-02] nb company save failure stays in the dialog and retry persists the retained draft",
|
||||
"state": "company-nb-failed-save",
|
||||
"file": "screenshots/company-nb-failed-save.png",
|
||||
"sha256": "6e375ea1661cbb27359aa020d93e9caf19d965a1d0bd0789f03f6f6cf09dcf03",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P6-02] nb failed account language preference reports local scope and retry persists",
|
||||
"state": "language-nb-failed-account-save",
|
||||
"file": "screenshots/language-nb-failed-account-save.png",
|
||||
"sha256": "2f2e6e3eca40c7204657c9c00a1e28c605e453a0033c675207867c3c0b59957e",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P6-03] en/light Settings panel relationships and reflow at 1920px",
|
||||
"state": "settings-1920x900-en-light-named-notification-panel",
|
||||
"file": "screenshots/settings-1920x900-en-light-named-notification-panel.png",
|
||||
"sha256": "3eb5b1545e8ee5b29efea63ad5b86f07d89dd8cd55f240268de3390ef75eb5c1",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P6-03] nb/dark Settings panel relationships and reflow at 360px",
|
||||
"state": "settings-360x900-nb-dark-named-notification-panel",
|
||||
"file": "screenshots/settings-360x900-nb-dark-named-notification-panel.png",
|
||||
"sha256": "026d7a70efd2685e142973a47021ffcbb52759c164a70077704d490eaf04deba",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P5-15-02 COLLECTION] thirteen areas retain native rendered entry across the distributed responsive/accessibility matrix",
|
||||
"state": "authentication-320x844-en-light",
|
||||
"file": "screenshots/authentication-320x844-en-light.png",
|
||||
"sha256": "4a4b967d8b289a464b6455079004ab1a746cb44307a0b787619f74918c4cdd9d",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P5-15-02 COLLECTION] thirteen areas retain native rendered entry across the distributed responsive/accessibility matrix",
|
||||
"state": "jobs-320x900-nb-dark",
|
||||
"file": "screenshots/jobs-320x900-nb-dark.png",
|
||||
"sha256": "0eb32112dd8d63ab80a1af8b3f78497bd1a4d6414a08fe3011b4341804107ed7",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P5-15-02 COLLECTION] thirteen areas retain native rendered entry across the distributed responsive/accessibility matrix",
|
||||
"state": "board-390x900-en-light",
|
||||
"file": "screenshots/board-390x900-en-light.png",
|
||||
"sha256": "89d5c24f8129d4cf0f722dcc527a7c38e468df837d336fcd029a39df201dc352",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P5-15-02 COLLECTION] thirteen areas retain native rendered entry across the distributed responsive/accessibility matrix",
|
||||
"state": "dashboard-1440x900-en-light",
|
||||
"file": "screenshots/dashboard-1440x900-en-light.png",
|
||||
"sha256": "4ab0e7170d827ad52637671d42079225dea4c9af11e71a2e4b3ae9d066e2aedc",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P5-15-02 COLLECTION] thirteen areas retain native rendered entry across the distributed responsive/accessibility matrix",
|
||||
"state": "analytics-390x900-en-light",
|
||||
"file": "screenshots/analytics-390x900-en-light.png",
|
||||
"sha256": "c1dc0d4a31e6e601295d9a70c7aba5b259dff07be5805062d82c64caac6597a4",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P5-15-02 COLLECTION] thirteen areas retain native rendered entry across the distributed responsive/accessibility matrix",
|
||||
"state": "workspace-320x900-en-light",
|
||||
"file": "screenshots/workspace-320x900-en-light.png",
|
||||
"sha256": "c2a4870e19b443dc35e28ad57a36d36d017a87b368b79ceb2350b5add695d79b",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P5-15-02 COLLECTION] thirteen areas retain native rendered entry across the distributed responsive/accessibility matrix",
|
||||
"state": "profile-390x900-nb-dark",
|
||||
"file": "screenshots/profile-390x900-nb-dark.png",
|
||||
"sha256": "15483561fbe643be550414c431489de69ca59197b2427b835d642b52729b3677",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P5-15-02 COLLECTION] thirteen areas retain native rendered entry across the distributed responsive/accessibility matrix",
|
||||
"state": "cv-1440x900-en-light",
|
||||
"file": "screenshots/cv-1440x900-en-light.png",
|
||||
"sha256": "0c4164f6c9ffc9523953b38925cdc46b80a6e913f01fce1e6766f5301c4d51f6",
|
||||
"inspectedByAgent": true
|
||||
},
|
||||
{
|
||||
"test": "[P5-15-02 C06 C09 C12] mobile edit-to-preview retains physical document measurement",
|
||||
"state": "mobile-preview-measurement",
|
||||
"file": "screenshots/mobile-preview-measurement.png",
|
||||
"sha256": "8b1467f5564703b4dd021a37fd693d0b128c6af56ba14c8ad6b0b16af65444b0",
|
||||
"inspectedByAgent": true
|
||||
}
|
||||
],
|
||||
"humanAcceptance": "NOT VERIFIED; agent inspection recorded separately"
|
||||
}
|
||||
@@ -68,7 +68,11 @@ The current builder already includes expandable sections, preset/free-text custo
|
||||
The [native readiness](../redesign/phase-5/p5-09-readiness/README.md) and [pagination repair](../redesign/phase-5/p5-09-pagination-readiness/README.md) now establish the bounded local preview/PDF contract requested during P4-03. P4-03 remains the keyboard/viewport proof. Later P5-11/P5-12 presentation/control work must retain this measured output baseline and explicitly carry broader photo/wrapping/deployment-font and print-quality qualifications; do not restart already-completed builder features from archived plans.
|
||||
|
||||
Completed phase items are intentionally omitted here; their evidence remains in the current redesign checkpoint records and recoverable historical archive.
|
||||
|
||||
# Phase 6 execution — 2026-10-11
|
||||
|
||||
- [ ] P6-00 baseline/design audit; P6-01 shared corrections; P6-02 workflow review; P6-03 responsive/accessibility/localisation; P6-04 performance/reuse; P6-05 acceptance/handoff. Track completed evidence and push hashes in [Phase 6](../redesign/phase-6/README.md). No Phase 7 implementation or production deployment.
|
||||
|
||||
- [x] P6-00 baseline/design audit, pushed `7da083c`.
|
||||
- [x] P6-01 shared corrections, pushed `a94ea0a`.
|
||||
- [x] P6-02 workflow/save/retry/localisation review, pushed `c135d03`.
|
||||
- [x] P6-03 bounded responsive/accessibility/localisation review and mobile Career label correction; native2/2 label and6/6 panel/label cases pass. Manual reader/device requirements remain open; push receipt follows in [Phase 6](../redesign/phase-6/COMMITS.md).
|
||||
- [ ] P6-04 performance/reuse; P6-05 integrated acceptance/handoff. Track completed evidence and push hashes in [Phase 6](../redesign/phase-6/README.md). No Phase 7 implementation or production deployment.
|
||||
|
||||
@@ -166,8 +166,34 @@ for (const [language, theme, width] of [['en', 'light', 1920], ['nb', 'dark', 36
|
||||
});
|
||||
}
|
||||
|
||||
for (const [language, theme, width] of [['nb', 'dark', 320], ['en', 'light', 390]] as const) {
|
||||
test(`[P6-03] ${language}/${theme} Career selector floating label is not clipped at ${width}px`, async ({ page, owner }, info) => {
|
||||
const sample: Sample = { area: 'profile', path: '/career?section=profile', width, language, theme };
|
||||
await enter(page, owner, sample);
|
||||
const navigation = page.getByRole('navigation', { name: translations[language].careerWorkspaceNavigation, exact: true });
|
||||
const label = navigation.locator('#career-workspace-section-label');
|
||||
const bounds = await label.evaluate(element => { const label = element.getBoundingClientRect(); const nav = element.closest('nav')!.getBoundingClientRect(); return { labelTop: label.top, labelBottom: label.bottom, navTop: nav.top, navBottom: nav.bottom }; });
|
||||
await info.attach('career-selector-label-geometry', { body: JSON.stringify({ sample, bounds, proofKind: 'Native CSS label bounds versus clipping navigation container; no human/device acceptance' }), contentType: 'application/json' });
|
||||
expect(bounds.labelTop).toBeGreaterThanOrEqual(bounds.navTop);
|
||||
expect(bounds.labelBottom).toBeLessThanOrEqual(bounds.navBottom);
|
||||
const evidence = await collect(page, info, sample, 'career-selector-label');
|
||||
expect(evidence.geometry.pageHorizontalOverflow).toBe(0);
|
||||
await navigation.getByRole('combobox').press('Enter');
|
||||
await page.getByRole('option', { name: translations[language].careerWorkspaceOverviewTab, exact: true }).press('Enter');
|
||||
await expect(page).toHaveURL(/\/career\/?$/);
|
||||
await expect(navigation.getByRole('combobox')).toHaveText(translations[language].careerWorkspaceOverviewTab);
|
||||
});
|
||||
}
|
||||
|
||||
test('[P6-04] measured native route, long CV and complete large Board workflows', async ({ page, owner, context }, info) => {
|
||||
test.setTimeout(360_000);
|
||||
const profileResponse = await page.request.get(`${apiUrl}/career/profile`);
|
||||
expect(profileResponse.status()).toBe(200);
|
||||
const profile = (await profileResponse.json()).profile;
|
||||
const sentence = 'Documented accessible services and reliable user workflows. Dokumenterte tilgjengelige tjenester og pålitelige arbeidsflyter. ';
|
||||
profile.jobs = Array.from({ length: 8 }, (_, index) => ({ id: `performance-role-${index}`, title: `Measured platform developer ${index + 1}`, company: 'Nordlys Audit AS', startDate: '2020-01', endDate: '2025-12',
|
||||
bullets: Array.from({ length: 4 }, (_, bullet) => `Evidence ${index + 1}.${bullet + 1}: ${sentence.repeat(3)}`) }));
|
||||
expect((await page.request.put(`${apiUrl}/career/profile`, { headers: owner.headers, data: { profile } })).status()).toBe(200);
|
||||
await context.addInitScript(() => {
|
||||
const observations = { longTasks: [] as number[], layoutShift: 0 };
|
||||
Object.assign(window, { phase6Performance: observations });
|
||||
@@ -206,7 +232,7 @@ test('[P6-04] measured native route, long CV and complete large Board workflows'
|
||||
const heading = (name: string) => async () => { await expect(page.getByRole('heading', { level: 1, name, exact: true })).toBeVisible(); };
|
||||
const t = translations.en;
|
||||
await measure('initial Jobs load', '/jobs', heading(t.jobApplications));
|
||||
await measure('Dashboard', '/dashboard', async () => { await expect(page.getByRole('heading', { name: t.dashboard, exact: true })).toBeVisible(); await expect(page.getByRole('progressbar')).toHaveCount(0); });
|
||||
await measure('Dashboard', '/dashboard', async () => { await expect(page.getByRole('heading', { name: t.dashboard, exact: true })).toBeVisible(); await expect(page.getByRole('link', { name: 'Tracked jobs: 6', exact: true })).toBeVisible(); });
|
||||
await measure('Analytics 6 months', '/analytics?months=6', heading(t.analytics));
|
||||
await measure('Analytics 24 months', '/analytics?months=24', heading(t.analytics));
|
||||
await measure('Job details', `/jobs/${owner.jobId}`, async () => { await expect(page.getByRole('heading', { name: /^Audit platform engineer 1/ })).toBeVisible(); });
|
||||
@@ -244,6 +270,40 @@ test('[P6-04] measured native route, long CV and complete large Board workflows'
|
||||
await measure(`Table ${size}`, '/jobs?view=table', heading(t.jobApplications));
|
||||
await measure(`Filtered Board ${size}`, '/jobs?view=board&q=Phase6%20capacity', async () => { await expect(page.locator('[data-kanban-card-id]')).toHaveCount(size - 6); });
|
||||
}
|
||||
const clientTimeOrigin = await page.evaluate(() => performance.timeOrigin);
|
||||
const clientRequests: string[] = [];
|
||||
const trackClient = (request: import('@playwright/test').Request) => { const url = new URL(request.url()); if (url.pathname.startsWith('/api/')) clientRequests.push(`${request.method()} ${url.pathname}${url.search}`); };
|
||||
page.on('request', trackClient);
|
||||
const tableLoaded = page.waitForResponse(response => new URL(response.url()).pathname === '/api/jobapplications' && response.request().method() === 'GET');
|
||||
let interactionStart = Date.now();
|
||||
await page.getByRole('link', { name: t.jobsTableView, exact: true }).click();
|
||||
const tableResponse = await tableLoaded;
|
||||
expect(tableResponse.status()).toBe(200);
|
||||
expect((await tableResponse.json()).total).toBe(994);
|
||||
await expect(page.locator('[data-job-row-id]').first()).toBeVisible();
|
||||
observations.push({ name: 'Client Board to Table retaining the large query', readyMs: Date.now() - interactionStart });
|
||||
interactionStart = Date.now();
|
||||
await page.getByRole('link', { name: t.jobsBoardView, exact: true }).click();
|
||||
await expect(page.locator('[data-kanban-card-id]')).toHaveCount(994);
|
||||
observations.push({ name: 'Client Table to Board retaining the large query', readyMs: Date.now() - interactionStart });
|
||||
const searched = page.waitForResponse(response => { const url = new URL(response.url()); return url.pathname === '/api/jobapplications/board' && url.searchParams.get('q') === 'Phase6 capacity 1000'; });
|
||||
interactionStart = Date.now();
|
||||
await page.getByRole('textbox', { name: t.jobTableSearch, exact: true }).fill('Phase6 capacity 1000');
|
||||
const searchResponse = await searched;
|
||||
expect(searchResponse.status()).toBe(200);
|
||||
expect(await searchResponse.json()).toHaveLength(1);
|
||||
await expect(page.locator('[data-kanban-card-id]')).toHaveCount(1);
|
||||
await expect(page.locator('[data-kanban-card-id]')).toContainText('Phase6 capacity 1000');
|
||||
observations.push({ name: 'Large Jobs search including existing debounce', readyMs: Date.now() - interactionStart });
|
||||
const dashboardLoaded = page.waitForResponse(response => new URL(response.url()).pathname === '/api/jobapplications/stats');
|
||||
interactionStart = Date.now();
|
||||
await page.getByRole('navigation', { name: t.navigation, exact: true }).getByRole('button', { name: t.dashboard, exact: true }).click();
|
||||
expect((await dashboardLoaded).status()).toBe(200);
|
||||
await expect(page.getByRole('link', { name: 'Tracked jobs: 1,000', exact: true })).toBeVisible();
|
||||
observations.push({ name: 'Client Jobs to Dashboard navigation', readyMs: Date.now() - interactionStart });
|
||||
expect(await page.evaluate(() => performance.timeOrigin)).toBe(clientTimeOrigin);
|
||||
page.off('request', trackClient);
|
||||
observations.push({ name: 'Client interactions request queries; unchanged document timeOrigin', timeOrigin: clientTimeOrigin, requests: clientRequests });
|
||||
await info.attach('phase6-performance', { body: JSON.stringify({ browserVersion: context.browser()?.version(), viewport: page.viewportSize(), environment: { platform: process.platform, application: process.env.PLAYWRIGHT_STATIC_EXPORT === 'true' ? 'production static export' : 'Next development server', prebuiltExport: process.env.PLAYWRIGHT_PREBUILT_EXPORT === 'true', serverReuseAllowed: process.env.PLAYWRIGHT_REUSE_SERVERS === 'true', database: process.env.PLAYWRIGHT_REUSE_SERVERS === 'true' ? 'reused server database not independently verified' : 'isolated synthetic SQLite from native test configuration', api: 'Release API from native test configuration' }, observations, limits: ['Single reproducible diagnostic, no production budget or device qualification', 'Hard-navigation measurements include boot/auth; no React render-count inference', 'CDP heap samples are observations, not a leak diagnosis'] }), contentType: 'application/json' });
|
||||
});
|
||||
|
||||
@@ -586,6 +646,11 @@ test.describe('Chromium emulated touch; not physical-device acceptance', () => {
|
||||
const navigation = page.getByRole('button', { name: t.openNavigation, exact: true });
|
||||
await navigation.tap(); await expect(page.getByRole('dialog', { name: t.navigation, exact: true })).toBeVisible();
|
||||
await collect(page, info, { ...sample, area: 'shell' }, 'emulated-touch-navigation');
|
||||
const drawer = page.getByRole('dialog', { name: t.navigation, exact: true });
|
||||
await expect(drawer.getByRole('button', { name: t.dashboard, exact: true })).toBeFocused();
|
||||
for (const name of [t.discoverJobs, t.companies, t.offerComparisonNav, t.trash]) await expect(drawer.getByRole('button', { name, exact: true })).toBeVisible();
|
||||
const settled = await collect(page, info, { ...sample, area: 'shell' }, 'emulated-touch-navigation-settled');
|
||||
expect(settled.axe.violations.filter(rule => rule.id === 'aria-command-name')).toEqual([]);
|
||||
await page.keyboard.press('Escape'); await expect.soft(navigation).toBeFocused();
|
||||
await info.attach('emulated-touch-boundary', { body: JSON.stringify({ hasTouch: true, input: 'Playwright Chromium touch tap', portraitLandscape: 'CSS viewport changes, not physical orientation sensor', physicalTouch: 'NOT VERIFIED', nativeTouchDrag: 'NOT VERIFIED', softwareKeyboard: 'NOT VERIFIED', cvUnchanged: true }), contentType: 'application/json' });
|
||||
});
|
||||
|
||||
@@ -334,8 +334,8 @@ export default function CareerProfilePage() {
|
||||
return (
|
||||
<Box sx={{ display: "grid", gap: 2 }}>
|
||||
<Paper component="nav" aria-label={t("careerWorkspaceNavigation")} variant="outlined" sx={{ borderRadius: 3, overflow: "hidden" }}>
|
||||
<FormControl size="small" fullWidth sx={{ display: { xs: "flex", sm: "none" }, p: 1.25 }}>
|
||||
<InputLabel id="career-workspace-section-label" sx={{ ml: 1.25 }}>{t("careerWorkspaceNavigation")}</InputLabel>
|
||||
<FormControl size="small" fullWidth sx={{ display: { xs: "flex", sm: "none" }, m: 1.25, width: "auto" }}>
|
||||
<InputLabel id="career-workspace-section-label">{t("careerWorkspaceNavigation")}</InputLabel>
|
||||
<Select
|
||||
labelId="career-workspace-section-label"
|
||||
value={workspaceSection}
|
||||
|
||||