Files
jobtrackingapp/docs/redesign/phase-5/p5-15/p5-15-01/rules-draft-repair/README.md
T

19 KiB
Raw Blame History

P5-15-01R-02 — Rules draft preservation

Source: c8e32238ef628f34c6ae8f64c6cb40ca5d8c68ac; development codex/ui-redesign-phase4. This checkpoint repairs P5-15-01-SETTINGS-01 only. Production main remains unchanged at 27657f31131cd95d42f0e1290853ec9c9b3959a4 and NO-GO. No Analytics repair, saved-search application change, P5-15-02, P5-13, Docker, B07 or deployment.

P5-15-01R-02: GO for the bounded Rules draft repair. Native retention, explicit save/discard/validation/retry, reload and account checks pass; all final applicable suites below have fresh results. The full ordinary browser command still exits1 for the separately retained AUTH-01 Analytics query-state defect. This is not an all-green application acceptance or production GO.

Reproduction and demonstrated root cause

A disposable authenticated Development/SQLite application seeds the actual six-field Rules record with Applied follow-up14. Edit that field to5, change Follow-ups→Notifications→Follow-ups. Before implementation, the browser observes14 on return while the database remains14 and zero Rules PUTs occur. The ordinary regression fails on the visible value: expected5, received14. It is not a mocked persistence response or missing-selector failure. Before/after native proof and fingerprints.

The former SettingsView.TabPanel returned null for inactive sections, unmounting RulesSettingsCard. Its component-local s held both fetched data and the unsaved draft. Returning mounted a new card, fetched persisted14 and replaced the destroyed draft. This is an editing-session ownership defect, not deletion/corruption of persisted rules. No evidence establishes which historical release introduced it.

The new ordinary browser regression was committed/pushed before application changes as 5b5dcd0b80aa0713545ecf1fdab079fb9dec28ee. Lower-level tests then reproduced the missing parent ownership/error/discard/race contract: a clean pre-fix Settings run had6passes/6failures. The old five tests and teardown case passed; six new desired-behaviour cases failed. The final Settings file now has13passing cases, including eight new cases over the inherited five:

  1. Preserve independent pending fields through tab unmounts, without PUT.
  2. Retain failed-save draft/error through tabs and explicit retry.
  3. Retain blank/out-of-range input and associated validation through tabs.
  4. Explicit Discard resets to the saved baseline without PUT.
  5. Pending save acknowledges5 while preserving newer dirty6.
  6. Old instance completion cannot affect a new Settings session.
  7. Changing UI language while Rules is hidden preserves its draft/no refetch.
  8. Rules editing leaves unrelated notification preference loading unchanged.

Actual workflow and persistence contract

  • Route /settings, Follow-ups tab or phone section selector. General, Follow-ups, Notifications and Backup are internal sections of the same Settings instance.
  • Authenticated local-account GET/PUT /api/rules, owned UserRuleSettings, RulesController. The current user comes from authenticated context; client record IDs/forged owner fields do not choose another user's record.
  • One atomic six-field configuration: appliedFollowUpDays, appliedGhostDays, offerFollowUpDays, offerGhostDays, feedbackFollowUpDays, feedbackGhostDays. Applied/Offer/Feedback are independent scenarios within one save, not three separately persisted rules.
  • GET retrieves/initializes the owner's configuration. PUT returns204 and clamps integer day values to1–365. The unchanged API has no revision/ETag or multi-client write-conflict contract.
  • Persisted baseline, unsaved session draft, pending save, validation/save errors, successfully acknowledged snapshot and explicitly discarded values remain distinct.
  • Internal section navigation retains the draft. Leaving Settings ends its in-memory session and discards unsaved changes, deliberately stated in the visible localized scope notice. No new cross-session recovery, automatic saving or browser storage is introduced.

Smallest responsible repair

File/component Change and reason
SettingsView Owns one Rules draft/baseline/load/save/error state above the existing unmounting panels; both tabs and phone selector use the same entry action. A single pending load is retained across transitions; loaded drafts are not refetched/reinitialized on tab return or locale change
RulesSettingsCard Controlled six-field form; retains existing labels/layout; explicit Save, bounded Discard, associated validation and durable localized load/save feedback. No API call or second local draft
Translations Three concise EN/Bokmål strings for successful save, integer day validation and the Settings-session draft boundary; existing Save/Discard/error labels reused
Settings regressions Eight behavioural cases added; original five retained
Native browser regressions Four ordinary cases using actual SQLite persistence/account APIs; no CSS class assertions, expected failures, skipped tests or live providers

Only three application-code files change. Settings is the shared owner; Rules is its sole form caller; translations are required for user-visible behaviour. No unrelated application file, backend, model, migration, API contract, dependency, renderer or deployment configuration changes.

Save validates all six strings as required whole numbers1–365 before PUT. This preserves blank/out-of-range input for correction rather than silently converting it to0/default or accepting the server clamp as successful input. Per-field helper text is associated with the input. Save submits a captured snapshot and acknowledges only that snapshot; if the user edits5→6 while5 is saving, completion records persisted5 while preserving dirty6. One pending submission is enforced. Discard returns to the last acknowledged baseline and writes nothing; it is disabled while a save is pending.

Failed save leaves all pending values and dirty state available, shows a durable in-page error, and permits explicit Save retry. No stack trace/provider text is exposed and no success is announced for failure. Invalid input/errors survive section changes. Existing authenticated-session invalidation and app/provider disposal remain authoritative; async completions from an unmounted Settings instance cannot set state/toast in a new instance. No second concurrency or identity system is added.

Behavioural evidence

Journey Fresh observed result
Original edit→tab→return **PASS:**14→5→return5; persisted14; zero PUTs, proving retention is not autosave
All six fields / repeated internal switches **PASS:**5/40/9/20/11/25 retained through two round trips in each of four variants; no cross-scenario draft substitution
Validation / internal return **PASS:**blank Applied and Offer366 retained with named associated errors; zero PUTs; correction permits normal save
Save failure / retry **PASS:**declared one-shot synthetic PUT500 retains draft/error across tabs; next real SQLite PUT204 persists all six values; dirty clears only after acknowledgement
Successful save / reload **PASS:**native GET and browser reload show the acknowledged values; all scenarios remain distinct
Explicit discard **PASS:**new Applied6/Offer10 returns to persisted5/9; no data mutation or implicit save
Delayed loading **PASS:**one held real GET across repeated transitions; loading is named; release initializes once, not over a newer draft
Pending save / newer edit **PASS:**submitted5, newer draft6, returned204, persisted5, dirty6; Discard restores5
Leave Settings / re-enter **PASS:**visible session warning; unsaved8 discarded deliberately; re-entry retrieves persisted5
Account switch / crafted owner / anonymous **PASS:**A persisted14/draft9; B forged owner/ID request updates only B22; A remains14; old page disposed and B displays22 without A draft; anonymous GET/PUT401
Locale switch / unrelated settings **PASS:**lower-level hidden Rules draft survives locale change without a new Rules GET; editing Rules does not trigger unrelated notification-preference refetch

The four focused browser cases pass4/4 with zero retries/skips/flaky/expected failures. Fault injection is limited to the explicitly declared PUT500 and held native reads/writes; ownership, persistence and readback exercise the real SQLite API. No server conflict semantics are invented.

Accessibility, localisation and responsive evidence

Actual variants: EN/light1440, Bokmål/dark768, EN/dark390, Bokmål/light320, height900. Desktop/tablet use keyboard activation of selected tabs; phones use keyboard section-selector opening/selection/focus return. Save/Discard activation, labelled numeric inputs, associated validation, non-colour dirty text and alert/status semantics are asserted. Reduced-motion is enabled for the matrix. Reflow checks test visible controls/text bounds, not specific CSS classes.

Focused evidence includes 16 screenshots and16axe scans;0reported violations;150incomplete node occurrences:142contrast and8hidden-focus. These are repeated occurrences, not150distinct defects or accepted checks. A coding-agent visual review inspected genuine EN desktop/light and phone/dark drafts, Bokmål dark tablet error, and320px Bokmål validation/discard images: fields, error text and actions remain readable, focus is visible, narrow content wraps. This does not certify human screen-reader announcements, physical touch/software keyboard, broader zoom or complete accessibility.

Representative images (all16 are in proof manifest):

Preservation traceability

Contract Existing behaviour → repair → evidence Current complete-group disposition
PRES-S03 Separate Rules/preferences scopes and explicit Save → parent session draft, associated validation, durable failure/retry/discard →13Settings cases +4native journeys +original diagnostic FAIL→PARTIAL, not PASS; notification contention/language persistence and full human/provider acceptance remain open
PRES-W11 Owned follow-up/ghosting configuration → same six-field atomic API/save and no auto-write → native six-value readback, forged-owner/anonymous cases, unchanged RulesEngineProspect backend regressions PARTIAL unchanged; scheduling/calendar/provider delivery and historical500 cause not qualified here
PRES-E07/E08 Reachable Settings navigation, locale/theme and feedback → shared tab/phone session entry, localized status/errors →four keyboard/reflow/theme/locale variants PARTIAL unchanged; broad human AT/device/zoom scope remains open
PRES-E09 Account-private draft disposal and stale-session rejection → retain existing API/session owner and suppress obsolete instance completion →native A/B/forged-owner/401 +component teardown PARTIAL unchanged; not a complete deployed/BFCache/session certification

All57 original contracts stay unchanged. Current complete-group totals after the scoped repair are PASS0 / PARTIAL55 / FAIL1 / DEFERRED1 / BLOCKED0 / NOT VERIFIED0 =57. E02 Analytics sign-in query loss remains FAIL; C11/P5-13 remains DEFERRED/Production-withheld. Original00,01 andR-01 statuses are retained in parent matrix. A PARTIAL group still contains unverified sub-workflows.

Fresh validation and diagnostic reconciliation

Backend1,033/1,033; frontend472/472 in82suites; revision5/5 and focusedAI108/108 are backend subsets; sidecar49 and configuration3 are fresh. TypeScript, lint, frontend production build and API/test-project Release builds pass. Frontend count464→472 is exactly eight new Settings behavioural cases. Backend count is unchanged; no backend test/model/contract changes.

All rows below are fresh after the final application change, not inherited success. Portable validation, exact commands/times, fingerprints and limits, native proof and final repository checks distinguish ordinary cases, subsets and independent suites.

Suite/check Fresh result Reconciliation
Backend full 1,033/1,033 Unchanged count; no backend production/test change
Frontend full 472/472,82suites 464+8new behavioural Settings cases; no failures/pending
Ordinary browser 128pass /1fail /129total R-01's125cases +4new Rules cases;117inherited,4audit,3saved-search and4Rules cases pass; AUTH-01 is the one real failure
Standalone preference diagnostics 2pass /0fail /2total Previously1pass/1fail; original Rules assertion now verifies retained5/persisted14/zero PUTs
Focused Rules native browser 4/4 Subset rerun, not four additional full-suite passes
Sidecar 49/49 Native JUnit; unchanged
Focused AI 108/108 Backend subset; deterministic, no configured-model qualification
Real HTTP 2/2 Actual API grounding/stale/account and Production withholding before provider/write; unrelated AI available
Revision safety 5/5 Backend subset; source/override/history/frozen references preserved
Standard fidelity 16/16;36preview=36PDF pages Same16fixtures, native output and unchanged predeclared tolerances
Settings exports 8/8;24preview=24PDF pages Same8exports/settings and unchanged tolerances
Rate-limit / ingress / PDF admission / configuration 9/6/1/3 Fresh separate local suites; not live F04/production evidence
Additional offline helpers Supply-chain3 / evaluation5 / extension3 Unchanged deterministic parser/config regressions; no Docker/provider execution
App/E2E TypeScript, lint, frontend production/API/test Release builds PASS Fresh static/build commands, zero exit codes; no renderer/deployment changes
Secrets, whitespace, docs/57-group/32-route hygiene PASS; final repository result Actual final checks exit0; original contracts/main unchanged and remote equals the pushed code checkpoint before the final documentation commit

The full browser command exits1 specifically at functional-acceptance.spec.ts:154: sign-in reaches /analytics without the requested ?months=6. No expectation was weakened, skipped or relabelled. P2-D01 passes normally. The original normal/admin saved-search failures and all three R-01 native repair cases remain passing; no saved-search code is touched. Both original diagnostic assertions now pass. Counts are not combined across overlapping suites/subsets.

All32route census patterns retain expected native entry/refresh/read states;98selected native GET observations include zero500s. The login query-continuity failure remains separate from entry/refresh and authorization. This repair does not reclassify full route-workflow acceptance.

Full-suite axe evidence is 267scans /0reported violations /2,040incomplete node occurrences: contrast1,768; hidden-focus41; prohibited-attribute209; valid-value18; table-header4. Focused16scans/150incompletes overlap and must not be added to the full totals. These are incomplete repeated occurrences, not passes or distinct confirmed defects. Human AT/device/zoom requirements remain open.

The prior R-01 CV “Unsaved” assertion passes in this unchanged full frontend run; native CV workflows also pass. It remains OPEN because its cause is unestablished. No CV assertion, timeout, implementation or renderer was altered to obtain a pass.

Intermediate tooling findings are retained separately: the first post-fix prebuilt browser attempt used API5202 while the disposable API was5302; correcting the test build environment resolved that harness issue. Two subsequent selectors were corrected to scope the existing Settings navigation and observe actual session-disposal navigation. No production code or product expectations changed to accept those failures. A required-input marker briefly changed exact labels; moving the native required attribute to the input restored existing accessible names. Final runs use the original required behaviour with retries0.

Outstanding obligations and risk

  • AUTH-01 Analytics sign-in query loss: ordinary known failure, untouched; remains before P5-15-02 progression is reconciled.
  • CV “Unsaved” intermittent assertion: prior R-01 failure has no demonstrated cause/fix; subsequent passing runs do not close it. Intermittent register.
  • Historical language-preference500, notification SQLite-lock contention and Rules-save500 root causes remain open. R-02 qualifies draft/error recovery, not a backend reliability repair.
  • Production provider and multi-client conflict qualification remain separate; native evidence here uses SQLite, not deployed MariaDB. No backend API conflict/version semantics are added.
  • Human screen reader, incomplete axe review, physical touch/software keyboard, production font/photo, broader pointer/reflow and Board scaling/touch debt remain open.
  • Production F04 ingress, current complete backup/tested restore, configuration/schema/secrets and tested rollback remain release blockers.
  • P5-05, P5-13 qualification/reviewUI and followMode compose UI remain explicitly deferred; unqualified AI Production withholding remains active, zero qualification calls/reviews performed.

Immediate commit/push ledger and stopping point

Completed logical unit Commit / boundary
Native RED regression, reproduction contract and bounded TODO 5b5dcd0b80aa0713545ecf1fdab079fb9dec28ee; pushed before implementation
Parent-owned Rules repair, eight component regressions, four native journeys and focused proof 30f513d0c993800ec5d5583329ed65dc7ec9a8d4; pushed after focused browser/full frontend/backend/static validation; remote equality and clean tree verified
Final acceptance/evidence reconciliation This documentation/evidence checkpoint; commit/push immediately after final repository checks. Its exact resulting hash and final remote/tree equality are reported to the owner after commit (no circular self-hash in this file)

Read-only subagent review found no actionable correctness/security issue; it inspected the sole caller, actual API/session disposal and snapshot/validation tests, and did not claim test execution or human acceptance.

P5-15-01R-02: GO for the bounded repair; Production remains NO-GO. P5-15-02 is not cleared by this checkpoint while AUTH-01 remains an unreconciled ordinary failure. Stop before Analytics repair, P5-15-02, P5-13, Docker, B07 and deployment.