Files
jobtrackingapp/docs/redesign/phase-5/p5-08b-readiness/README.md
T

19 KiB
Raw Blame History

P5-08b readiness — native packages and workspace boundaries

Source checkpoint: fadf99a3f55f7cb8bcd85fe489c46259f525f3ef, branch codex/ui-redesign-phase4. This is a readiness checkpoint, not P5-08b's seven-section visual migration. No schema, provider, authentication, rendering, mail-send, B07 or CV revision change.

Acceptance decision

GO for the bounded P5-08b presentation migration. Native package preservation, navigation and the scoped accessibility prerequisites have passed the final validation below. Existing links, section history and followMode retention are protected. The Phase 3 route plan additionally required opening the actual compose/follow-up mode. Current source has producers of followMode and a backend follow-up-draft endpoint, but no frontend consumer of that parameter or that endpoint. Correspondence logs messages/imports threads; ApplicationFollowUp edits dates/actions. Neither is a mode-specific reviewed email composer.

Connor's explicit decision, 2026-10-07: “Preserve metadata; defer mode-specific UI.” This supersedes the assumed compose-mode activation requirement for this readiness gate and P5-08b. Preserve followMode without interpreting it as send, generation or submission; mode-specific reviewed UI remains mail-phase work. No functionality is claimed for the absent consumer, and the historical route-plan assumption remains visible. This checkpoint does not implement messaging or the deeper redesign.

Actual native package model

Concept Existing owner and contract
Live/draft application JobApplication: CoverLetterText, TailoredCvText, RecruiterMessageDraft, status/dates/source/job metadata and Notes. Application answers occupy the existing delimited Notes block; human notes remain separate through the existing helper. A generated draft is not a submitted package.
Canonical profile and CV CareerProfileService owns canonical data/history; CvVariantService owns settings, versions, rendering and current single-job association. ApplicationAssetsService.AttachVariantAsync attaches/reassigns one variant or detaches without deletion. No many-to-many association is introduced.
Frozen package SubmittedApplicationPackage, explicitly captured through ApplicationAssetsController: append-only version per owner/job, scalar source CV ID/name/version/theme/settings, canonical profile JSON, rendered HTML, exact cover letter and application material JSON. Capture does not prove external delivery or change job status.
Frozen files SubmittedPackageAttachment: copied bytes, original display filename/type/purpose, length and SHA-256. Native AttachmentStorage stores copies below the existing job submitted/<version> directory. Live deletion cannot delete that independent snapshot.
Review/download Owner/job/package-qualified list/detail and attachment download endpoints. SubmittedPackagesSection reopens frozen HTML/letter/material; physical-file download uses the preserved filename/type. There is no package-update endpoint.
Archive Existing account export jobtracker.user-export.v1 ZIP: data/application-workspace.json contains frozen package metadata/content; files/submitted-packages/<packageId>/<attachmentId>/<safe filename> contains bytes; manifest.json records paths/lengths/hashes. This is an account archive, not a newly introduced package ZIP format.
Restore/import Existing cover-letter restore appends a new history version. Package reopening/readback is supported; no submitted-package import/restore-to-live operation exists. ZIP readback uses native ZipArchive/ZipFile, not an invented import workflow. Existing whole-database restore/deployment proof is separate.
Ownership Controllers derive the user from authenticated identity; services qualify owner plus job/variant/package/attachment. EF tenant filters supplement these explicit predicates. Account export bypasses filters only with its existing explicit owner qualification.

Frozen CV ID is a scalar historical identifier, not a new mutable FK to the current CV. Job/package attachment cascades and the unique owner/job/package-version index are unchanged. Deleting the entire account/job follows existing retention/deletion policy; this proof concerns preserving a package while its live sources change.

Reproductions and smallest fixes

  • P2-D01: the original native browser case reproduced capture HTTP 500 with expected status failed; later archive assertions were unreachable. A new real-SQLite regression failed with NotSupportedException: SQLite does not support expressions of type 'DateTimeOffset' in ORDER BY clauses at GetTailoringPlanAsync. Capture had the same unsupported variant ordering. Reuse the already established provider branch in BuildCvAsync: filter by authenticated owner/job in SQL, order materialized owner-filtered values only on SQLite; retain SQL ordering for other providers. No timestamp conversion, schema or package-content change.
  • P3-O02: setParams({section}) dropped followMode and unrelated existing query metadata. Clone the current query and replace only section, retain router state and push genuine section navigation so browser Back/Forward can traverse it. Compatibility aliases remain replace redirects in their existing route owner.
  • P5-08a-O01: legacy Overview aliases previously selected Overview without revealing their deeper content. Existing accordions now open/focus their matching disclosure for job-details/checklist/documents/portfolio/timeline/communication. notes resolves to the existing answer/letter owner. The complete-career-profile system task opens the existing /career?section=profile; no new wizard or client progression engine. Unknown/prototype keys fall back safely.
  • P5-08a-O03: AccordionDetails repeated the region ID MUI already generated. Remove that redundant ID and scope summary/region identities with React useId. Add explicit selected-tab/panel relationships around the existing five sections; retain MUI's manual-activation keyboard behavior.
  • P4-02-D04: supply the existing coverAiUsing interpolation parameter instead of showing literal {name} and an appended duplicate name. No AI context/prompt/API change.
  • Keyboard checklist prerequisite: desktop move/dismiss controls were transparent until pointer hover. The existing row also reveals them on focus-within; names/actions/data are unchanged. Native browser tests verify the focused move control is actually visible.

Native preservation invariants and proof

  1. The real disposable API/browser fixture creates an ordinary account, canonical profile with Åse/Nordlys/Norsk data, two CVs, one job, reviewed letter, answer/recruiter drafts and UTF-8 attachment. Tailoring returns 200; capture through the existing UI returns 200.
  2. Record package ID/version, source CV ID/version and file metadata. Mutate current CV settings/name, canonical profile, letter and answers; delete the live file and detach the CV. Frozen detail is exactly equal before/after; the sibling CV is unchanged and detached CV remains readable.
  3. Download the preserved attachment after live deletion and compare exact bytes. Reopen the package dialog after reload. Restore letter version 1 as new version 3; the frozen detail remains unchanged.
  4. A second real account receives 404 for package list/detail/file, capture of the first account's job and crafted foreign-CV association, including attaching A's variant to B's own job.
  5. The new backend native test uses SQLite, real CareerProfileService, CvVariantService, ThemedCvRenderer, AttachmentStorage, AccountOwnedFileInventory and AccountDataExportService. Reopen the real ZIP; compare frozen HTML/letter/material/source identity/profile/purpose and exact attachment bytes. Match the manifest SHA-256. Only current-user/host setup is mocked; packaging/rendering/storage are not.
  6. A second native backend fixture captures a sparse package with no CV/letter/files. A later capture copies one available file, then encounters a missing second source: it throws, publishes no partial package and purges the already copied file. Restoring the missing source allows explicit retry as version 2 with both files.

Dynamic creation timestamps, generated IDs and ZIP compression/container bytes are not compared across independently created archives. Meaningful content, relationships, source identity, metadata and original file bytes are compared. No real AI/provider, external send or PDF geometry claim follows from HTML/package proof.

Navigation and accessibility evidence

  • Four native browser cases exercise EN/NB × light/dark, all ten buildJobWorkspacePath numeric inputs, existing direct sections, reload, manual keyboard tab selection and Back/Forward, retaining followMode=waiting-update throughout. Numeric inputs are helper arguments, not a newly supported section=3 URL convention.
  • Named legacy disclosures become reachable on direct entry; keyboard focus moves to their summary. Tabs retain native Arrow/Home/End focus movement and Enter/Space activation rather than pretending pointer buttons are tabs. The labelled panel is the next keyboard stop; section changes do not trigger sends/generation.
  • Component tests prove selected-tab/panel association, a unique named accordion region, document disclosure focus, query retention, canonical-profile next action and the existing dirty Cancel/Discard/list-return guards.
  • Existing full-suite fixtures retain Jobs → Job → browser Back row focus, missing/foreign jobs, account-switch disposal, attachment consent, application answer versus human Notes, AI edited acceptance/rejection and provider-unavailable behavior. These are distinct test layers; provider mocks do not prove live AI/mail.
  • Scoped navigation axe scans and rendered screenshots are recorded separately. A scoped scan is not whole-workspace certification. Manual screen-reader spoken names/live announcements remain open for P5-15; physical touch/zoom and previously incomplete checks remain explicit gaps.

No permission-restricted section is newly exposed: existing five purposes remain visible, their original controls/backend enforce entitlement/ownership. No disabled feature is turned into a functional control, and no new seven-section navigation is introduced.

Preservation traceability and changed files

PRES contracts Existing requirement → readiness change Proof
W01, E07/E08/E09 Existing routes/section/query/return context → retain query/history, reveal existing aliases and label existing panels application-workspace-overlay.test.tsx, applicationWorkspace.test.ts, four native navigation cases and existing Jobs/auth browser suites
W04/W08/W11 entry Existing checklist/documents/history/calendar → focus their existing disclosures; keyboard checklist actions remain visible Native numeric-helper/disclosure/reload/keyboard cases; unchanged domain regression suites
W05/W06/W07, C01/C05/C07/C10 relationships Canonical versus variant, letter/answer and frozen evidence → provider-compatible native capture; no domain redesign Native SQLite/archive/failure-retry tests and expanded real browser immutable-package case
W03/W06, C11/S04 dependency Known AI source/review → correctly interpolate existing source label Existing AI accept/reject tests plus label assertion; no provider factual certification
M01/M02, W09/W10/W12 dependency Mail/interview/operations owners retained Complete inherited suites; absent followMode UI explicitly deferred to mail phase by Connor, metadata retained

Production changes are confined to ApplicationAssetsService.cs, SubmittedApplicationPackageService.cs, applicationWorkspace.ts, ApplicationWorkspacePage.tsx, one source-label line in ApplicationAssets.tsx, and one focus selector in ApplicationChecklist.tsx. Tests: native compatibility file, existing workspace/helper/assets Jest files and redesign-preservation.spec.ts. No component extraction, page restyling, route/provider-tree change, dependency or CI change.

Final validation

Inherited baseline: 934 backend / 408 frontend / 83 actual browser passes plus P2-D01 expected failure; security 9/6/1 and configuration 3. Commands below use the repository's rtk proxy prefix; npm commands run in job-tracker-ui, other commands at repository root. Browser suites share the disposable API port and run sequentially.

Final command Result
C:/Users/Connor/.dotnet/dotnet.exe test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj -c Release --no-restore --logger 'console;verbosity=minimal' 936 passed, 0 failed/skipped; +2 native SQLite/package/ZIP and sparse/failure/retry cases
npm.cmd test -- --runInBand --silent 412 passed, 80 suites; +4 workspace query/panel/disclosure/canonical-entry cases; existing helper and AI-review cases strengthened without extra case count
npm.cmd run test:e2e -- --reporter=line,json with PLAYWRIGHT_STATIC_EXPORT=true, PLAYWRIGHT_PREBUILT_EXPORT=true, PLAYWRIGHT_JSON_OUTPUT_NAME=test-results/p5-08b-readiness-final.json 88 actual passes, zero expected failures/unexpected outcomes, 14.7 minutes; four new cases plus P2-D01's expected-to-actual transition
npm.cmd run test:rate-limits -- --reporter=line 9 passed
npm.cmd exec playwright test -- --config=playwright.ingress.config.ts --reporter=line 6 passed
npm.cmd run test:pdf-admission -- --reporter=line 1 passed
npm.cmd run typecheck / npm.cmd run lint Both passed
npm.cmd run build with NEXT_PUBLIC_API_BASE_URL=http://localhost:5302/api Production static export passed
C:/Users/Connor/.dotnet/dotnet.exe build JobTrackerApi/JobTrackerApi.csproj -c Release --no-restore -warnaserror Passed, zero warnings/errors
npm.cmd exec tsc -- --project ../.artifacts/p5-08b-readiness-e2e-tsconfig.json --noEmit --incremental false Edited browser fixture TypeScript passed, using existing Node/Jest types; no dependency/CI change
python scripts/test-ingress.py 3 configuration tests passed
python scripts/test-supply-chain.py 3 passed
python scripts/test-ollama-evaluation.py / node browser-extension/tests/capture-url.test.mjs 5 / 3 passed; these local checks do not certify live providers
python scripts/supply-chain.py scan-secrets Passed on staged candidate, no high-confidence credential patterns
git diff --check / git diff --cached --check Passed
python .artifacts/p4-04-check-doc-links.py 142 current/root Markdown documents, zero missing local targets; historical archive excluded

The two added backend tests are Tailoring_and_submission_capture_work_on_native_sqlite and Native_sparse_capture_and_missing_attachment_retry_never_publish_partial_packages. Four new browser cases cover EN/NB × light/dark. The original P2-D01 case is retained by name with ordinary capture/readback assertions; its old expected-failure branch is removed only after the initial native 500 was reproduced and successful post-fix preservation was observed. P2-D01 is closed for the reproduced local SQLite failure. Counts change from 83 actual + one expected to 88 actual: +4 new cases, +1 genuinely passing original case. No skipped/expected branch masks capture, frozen readback or archive failures.

Raw disposable-browser traces/authentication outputs remain ignored. The safe final browser summary, native invariant summary, scoped axe results and reviewed screenshot manifest preserve the useful evidence. Four tablist scans each have zero violations and zero incomplete findings within that scope only. Unrelated/full-page incomplete checks and human screen-reader acceptance remain open.

Rendered review and evidence limits

Reviewed all 13 native screenshots: desktop 1280×720 and phone 390×844, EN/NB × light/dark, focused checklist move, directly opened Documents disclosure, selected Analysis content and reopened frozen package. Existing theme surfaces, readable labels and visible disclosure/checklist focus remain. No section layout or styling redesign was performed.

The manifest records these limits explicitly:

  • Full-page images taken after programmatic focus scrolling show fixed shell elements at the current scroll position in the stitched capture. This is not evidence that the shell was moved or proof of viewport-level overlay clearance.
  • The immediate post-Forward screenshots catch the tab indicator in transition; automated selected-tab/content/query assertions pass, but those PNGs do not certify settled animated indicator alignment.
  • The native package-dialog image catches its entry transition. It is not accepted as settled modal contrast/readability proof; native immutable content and ZIP assertions are separate. The existing shared-dialog/manual accessibility debt stays open.
  • The existing narrow attachment table/empty-message clipping and backend-generated English analysis/event text in Bokmål remain domain/presentation debt for the later workspace/localisation owners. Readiness makes their existing entries reachable; it does not redesign them.

No whole-workspace axe, spoken screen-reader, production MariaDB or PDF geometry acceptance is inferred from these focused fixtures. Manual review here means inspection of actual rendered captures; keyboard proof is automated native browser interaction, not a human assistive-technology session.

Validation observations: initial NB navigation fixtures failed because local language setup was overwritten by native account preference hydration. The fixture now saves the existing authenticated language preference (requires 204) before app mount; no language/provider behavior was changed. The first local browser-only TypeScript configuration could not resolve Node types from .artifacts; the ignored configuration now points at existing frontend type roots. Neither is an application repair or weakened assertion. Historical P2-D01 and unrelated failures remain in their original records.

Remaining limitations and stop boundary

followMode compose-mode activation is not demonstrated and is explicitly deferred by Connor to the mail phase. Package version/revision concurrency is not redesigned here; source lost-update guards and CV geometry remain separate gates. SQLite evidence ordering materializes the same owner-filtered set already used by subsequent relevance filtering; no global/unscoped load is introduced. MariaDB query translation is tested, not a live production database.

Keep F04, P5-02 manual screen-reader acceptance, incomplete/manual accessibility checks, preference-save 500/SQLite contention, Board scaling/native touch, shared-dialog focus observations and CV revision/rendering debt open. P2-D01 closes with the successful native post-capture proof and final ordinary browser case, not by hiding its old expected failure. Historical audit/Phase 2/P4 records remain untouched except for explicit successor links; the Phase 3 route plan has an explicit successor clarification for Connor's approved metadata deferral.

Stop before P5-08b, P5-09 and B07. A subsequent instruction may authorize the bounded P5-08b presentation migration under these preservation contracts; the GO does not authorize CV revision/rendering changes, new messaging or production release.