Files
jobtrackingapp/docs/redesign/phase-9/rd21-remediation/ACCEPTANCE_ADDENDUM_2026-10-23.md
T

12 KiB

RD21 acceptance addendum — 23 October 2026

The reproduced SQLite stale-write and partial-commit defects are repaired and locally verified. Formal RD21 remains UNRESOLVED because the unchanged issue requires supported MariaDB runtime evidence. Phase 9, Phase 10 readiness and production remain NO-GO.

This supplements the original Phase 9 acceptance; it does not rewrite its historical findings or approval boundaries. The remediation uses the requested fix/rd21-acknowledged-edit-loss branch from final Phase 9 8e7e3f6387544e24082ebe2c107c0b868897959e. Qualified product checkpoint: 1b89a77.

Separate acceptance decisions

Decision Disposition and evidence boundary
A. RD21 UNRESOLVED (qualification). SQLite implementation repair passes. The original required closure evidence explicitly includes MariaDB runtime constraints, held readers/writers and partial failure. That qualification remains absent.
B. Phase 9 functional QA NO-GO. Local remediation assessment and complete automated regression are finished, but formal RD21 and original output/provider/manual conditions remain open.
C. Human accessibility/device acceptance Outstanding. Fresh automated route/accessibility diagnostics do not replace NVDA/VoiceOver, physical touch/drag/software keyboard, forced colours, human zoom/reflow or professional Bokmål review. Original manual rows remain.
D. Provider/database qualification SQLite verified locally; MariaDB NOT TESTED. No inference from SQLite or SQL generation to MariaDB runtime. External providers, enabled-worker recovery and model semantics remain separate.
E. Phase 10 readiness NO-GO. Preserve all routes, compatibility paths, canonical/CV/frozen boundaries and remaining criteria. This handoff authorizes no cleanup/deletion or Phase 10 implementation.
F. Production NO-GO. Storage faults, backup/restore/rollback, live advisories, deployment identity, ingress and provider/manual gates remain. No production database, migration, service restart, filesystem repair, deployment or model action occurred.

Reproduction and exact root cause

The unchanged original characterization ran at the exact baseline using two independent authenticated clients and synthetic SQLite data. Both clients read one record. A successfully saves a changed summary/title; B submits its older complete snapshot with a different field changed. Career accepts B with 200; jobs accepts B with 204. Fresh reads restore A's field to its old value: both lostFirstEdit=true. Its one passing characterization is evidence of unsafe behavior, not a safety pass. Captured observations.

Both domains lacked the editor's source precondition on replacement writes. Career incremented an internal version without comparing the source revision or enforcing it as an EF concurrency token. Jobs had no equivalent revision token. A new request could therefore load the current row and replace it with arbitrarily old client fields. The optional awaited job summary also left a read/write interval that a controller-only comparison could not protect.

Career had a second proven failure: the canonical aggregate transaction committed before the controller's Identity projection update. Injecting an Identity failure left canonical content changed despite a failure response. Parse and reviewed import acceptance shared that split boundary. Native SQLite RED tests capture persisted loss and partial commits; see before-regressions.json and root-cause analysis.

Implemented correction

Career source snapshots expose a coherent revision. Manual save, history restore, parse and reviewed import acceptance require that revision. EF compares the original version at the eventual database write, and competing first saves use the existing unique owner constraint. Canonical children/history, raw text, Identity projection and applied-import metadata commit in one transaction. Failure rolls back and clears failed tracked changes. GET no longer backfills unversioned canonical data. The obsolete identity-only CV projection bypass fails closed.

Jobs have an application-managed EF concurrency token, advanced by every tracked job mutation. Generic replacement and directly related cover-letter, application-answer and legacy tailored-CV snapshot writers require their source revision. Related persisted text loss was reproduced before extending the correction. Opportunity/timeline changes remain in the same SaveChanges transaction; rejected requests append no success history or side effects. Generic Notes editing preserves the separately embedded application answer and validates company ownership.

Clients keep source revision and draft together. They acknowledge saves after successful server responses, retain rejected/network-failed drafts, exclude overlapping edits and late modal/read responses, and require deliberate review/reload after conflict. They never fetch a newer revision to authorize an older body. Whole-branch review found two integration defects: the committed job header was hidden by CORS, and Answers could mount from a stale overview after a sibling write. Both received deterministic RED evidence, one fix wave and a clean scoped re-review. Actual cross-origin JavaScript and native successive saves prove the repaired integration.

SAVE_CONTRACT.md specifies endpoint/status/revision compatibility. Older unversioned replacement clients intentionally fail closed: missing Career preconditions return 400, stale Career returns 409, and missing/invalid/stale job revisions return 409. Existing 204 job writes return the committed X-Job-Version, exposed by the allowlisted credentialed CORS policy. No automatic stale retry, silent merge, arbitrary delay or new dependency was added.

Completed verification

Lane Actual final result
Backend Release 1,109 passed, zero failed/skipped, exit 0; actual SQLite persisted-state, overlap, rollback, tenant, first-save, stale restore/import and populated migration upgrade/rollback/reapply coverage.
Frontend Jest 934 passed / 105 suites, zero failed/pending/todo, exit 0 on final source.
Ordinary browser 362 passed: serial shards 98 + 87 + 88 + 89; exact unique discovery membership, four exit 0 outcomes, no run errors/retries/skips/flakiness.
Separate browser contracts 23 passed: AI withholding 2, auth recovery 2, rate limits 9, ingress 6, PDF admission 1, preferences 3; no retries/skips/flakiness.
Sidecar 56 passed, zero failed/skipped, exit 0; SKIP_MODEL_LOAD=1, no model semantics claim.
New remediation browser 6 passed, no retries/skips: original A/B ordering, independent immediate SQLite reads, navigation/refresh/new authenticated session, missing revisions, native draft retention/recovery, actual cross-origin header, successive Answers saves and fresh source entry after letter save; includes conforming bounded sustained workload.
Conforming volume companion 3 passed: 100 CV revisions/additive restore, 100 exact timeline messages and 100 cancellation notifications/ownership/counts. Only Career seed revision supplied; original assertions retained.
Unchanged historical diagnostics 16 passed / 2 failed, exit 1: old Career seeds in data.spec.ts and sustained.spec.ts expect 200 without a revision and receive 400. Actual failures retained; zero skipped/retried.
Unchanged historical volume 2 passed / 1 failed, exit 1: old CV-volume Career seed also expects unversioned 200 and receives 400. Actual failure retained.
Types/lint/build Final full TypeScript and ESLint exit 0; API Release and UI static export builds pass. New companion diagnostics receive separate TypeScript checking. No deployment.
Offline security Supply-chain 3, evaluator 5, browser-runtime 6, ingress 3, Node dependency/SMTP 15 and extension 3 pass; tracked-secret scan passes and SBOM generated. No live advisory refresh.
Native PDF oracle 16/16 standard fixtures, 36 pages; 8/8 Settings fixtures, 24 pages. Unchanged oracle/tolerances, exact membership/page counts, inputs hashed before/after verification against final shard-produced bytes. Automated fidelity evidence; no new human/print/device acceptance.

validation.json retains exact cases, process timestamps/exits and report hashes. The final source manifest binds 878 inputs, SHA256 7487f343786928e90a3c8a740571c29e5c934c80fa822abb80c7a39483e1353b, including source, active fixtures, historical diagnostics, static export and API/test assemblies. Source checks before ordinary shards and after final diagnostics found no drift. The later conforming volume copy has separate original/copy hashes in its fixture provenance.

The unchanged original reproduction was rerun and intentionally retained its actual post-fix failure at the now-invalid unversioned seed. The conforming companion preserves the same A/B read/write ordering with each source revision and stronger assertions: A's commit is read directly from SQLite immediately after acknowledgement; B receives 409; A's values/history/projection remain after rejection, navigation, reload and a new authenticated session. This is an explicit contract adaptation, not a changed historical test or an assertion that the old fixture passed.

Counts are separate lanes, never summed into a blanket all-green total. Focused tests overlap full suites; initial remediation 4 and focused integration 2 overlap final 6. Pre-review Jest 930 is superseded by final 934. One earlier ordinary run was interrupted after 22 passes for confirmed review findings and is not a completed suite. Baseline unsafe characterization and native RED records remain. The initial job RED runner overwrote its first raw TRX; that provenance limitation is disclosed in before-regressions.json rather than replaced with fabricated raw evidence. The finite sustained run shared its host with frontend/static qualification work; it is a bounded correctness workload and cannot establish an uncontended performance baseline or SLA.

Provider, preservation and remaining risks

Docker default, desktop-linux and desktop-windows read-only probes failed because engine named pipes were absent. No native MariaDB/MySQL executable or common Program Files installation was found. No service installation, restart, download or production access was attempted. MariaDB concurrency/first-save constraints/held-reader-writer/partial rollback must be exercised on an isolated disposable supported instance before formal closure. Do not infer deployment safety from a generated SQL script or the local SQLite migration test.

All 57 groups and 33 routes remain; 56 PARTIAL / C11 DEFERRED, zero upgrades to PASS. Original remaining criteria and historical observations are retained in the reconciliation. Canonical versus CV-specific null-as-inherit overrides, append-only revisions and submitted/frozen archives retain their passing native contracts. The related review distinguishes already-guarded Dashboard/CV/email drafts, narrow job lifecycle commands and independent settings/company/contact records. This is not complete multi-session acceptance of every independent editor.

Historical overwritten edits are not proven recoverable. Existing history may help a specific record, but no live records were inspected and no recovery is claimed. Creation-intent idempotency remains separate and unimplemented. Extraction discard-versus-accept lifecycle concurrency was considered but not reproduced; it is not certified by these replacement-write tests. Unknown network outcomes still require deliberate current-data review before retry. Mixed old/new clients and servers, real MariaDB and production rollback remain unqualified; schema downgrade does not preserve revision identity. Original duplicate reminder GET and raw Created terminology findings remain separate low-priority observations.

Next qualification: run the same persisted-state, transaction/tenant and migration contracts on disposable MariaDB; complete the original manual/provider/output/release gates; then reassess RD21 and Phase 9. Phase 10 receives this blocked handoff only. No main merge, production action, model activation, new integration or Phase 10 implementation is authorized by this addendum.