docs(redesign): record Rules draft repair acceptance
This commit is contained in:
@@ -1,28 +1,146 @@
|
||||
# P5-15-01R-02 — Rules draft preservation
|
||||
|
||||
Source: `c8e32238ef628f34c6ae8f64c6cb40ca5d8c68ac`, development `codex/ui-redesign-phase4`. Production `main` remains unchanged/NO-GO. This checkpoint owns SETTINGS-01 only; Analytics, P5-13, P5-15-02, Docker and B07 are excluded.
|
||||
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.
|
||||
|
||||
## Demonstrated reproduction before implementation
|
||||
**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.
|
||||
|
||||
The new ordinary browser regression uses a disposable authenticated SQLite application. Seed the existing six-field Rules configuration (Applied follow-up14); edit it to5; switch Follow-ups→Notifications→Follow-ups. The entered5 becomes14, the persisted value remains14, and zero Rules PUTs occur. The run fails on the actual visible value (`expected5, received14`), not a mocked server or missing selector. Raw trace/report: ignored `.artifacts/p5-15-01R-02/browser/rules-red.*`.
|
||||
## Reproduction and demonstrated root cause
|
||||
|
||||
`SettingsView.TabPanel` returns null for inactive sections, unmounting `RulesSettingsCard`. The card's local `s` state is both its initially fetched data and edited draft. Returning creates a new card, performs a new GET and initializes from persisted14. This is destruction of editing-session state, not a backend write or deletion.
|
||||
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](evidence/rules-proof.json).
|
||||
|
||||
## Bounded repair contract
|
||||
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.
|
||||
|
||||
- Move the single Rules draft, persisted baseline and load/save/error state into the existing Settings parent. Inactive forms may still unmount; no keep-all-tabs-mounted workaround, browser storage, cross-session draft or automatic save.
|
||||
- Preserve the existing per-account six-field atomic GET/PUT contract: Applied, Offer and Feedback are separate scenarios within one configuration, not three separately saved records. PUT returns204; the API clamps integer day values to1–365 and has no revision/ETag contract.
|
||||
- Internal tab/phone-section changes preserve pending fields/errors. Save submits one validated snapshot; failure retains it; later edits during a pending save must stay dirty. Explicit discard returns to the latest successful baseline without a write.
|
||||
- Clearly communicate the in-memory Settings-session boundary. Existing authentication/session disposal remains authoritative; no global draft store or second identity boundary.
|
||||
- Keep S03 and W11 traceability, E07/E08/E09 reachability/accessibility/account protection. Full-group acceptance requires other retained sub-workflows; this repair alone cannot grant PASS.
|
||||
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:
|
||||
|
||||
## Checkpoint plan / current status
|
||||
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.
|
||||
|
||||
- [x] Trace and reproduce the exact native draft loss.
|
||||
- [x] Add the ordinary failing browser regression before application changes.
|
||||
- [x] Repair and validate controlled draft/save/discard/error ownership.
|
||||
- [x] Complete focused native/browser, localisation/responsive and account evidence.
|
||||
- [ ] Run the fresh full baseline and reconcile ordinary failures/counts.
|
||||
- [ ] Update acceptance/defect evidence, commit/push each completed unit and verify clean remote equality.
|
||||
## Actual workflow and persistence contract
|
||||
|
||||
The reproducer was committed/pushed as `5b5dcd0b80aa0713545ecf1fdab079fb9dec28ee` before implementation. The bounded implementation now passes all four native SQLite browser journeys and all472 frontend tests (464+8 focused behavioural cases), TypeScript, lint and the production build. Backend1,033, focused AI108, revision5 and sidecar49 have fresh passing runs. The complete browser/security/document run is in progress; no final browser count or repair acceptance is claimed here. The original audit and R-01 evidence remain unchanged. Production NO-GO and all deferred qualification obligations remain open.
|
||||
- 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](../../../../../../job-tracker-ui/src/components/SettingsView.tsx) | 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](../../../../../../job-tracker-ui/src/components/RulesSettingsCard.tsx) | 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](../../../../../../job-tracker-ui/src/i18n/translations.ts) | 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](../../../../../../job-tracker-ui/src/settings-view.test.tsx) | Eight behavioural cases added; original five retained |
|
||||
| [Native browser regressions](../../../../../../job-tracker-ui/e2e/rules-draft-repair.spec.ts) | 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](evidence/rules-proof.json)):
|
||||
|
||||
- [Desktop EN/light draft and focused navigation](evidence/rules-draft-en-light-1440.png)
|
||||
- [Tablet Bokmål/dark save failure](evidence/rules-save-error-nb-dark-768.png)
|
||||
- [Phone EN/dark draft](evidence/rules-draft-en-dark-390.png)
|
||||
- [Narrow phone Bokmål/light validation](evidence/rules-validation-nb-light-320.png)
|
||||
- [Narrow phone explicit discard](evidence/rules-discard-nb-light-320.png)
|
||||
|
||||
## 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](../../PRESERVATION_ACCEPTANCE.md). 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](evidence/validation.json), [native proof](evidence/rules-proof.json) and [final repository checks](evidence/repository-validation.json) 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](evidence/repository-validation.json) | 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](../INTERMITTENT_FAILURES.md).
|
||||
- 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.
|
||||
|
||||
Reference in New Issue
Block a user