test(qa): qualify route matrix and document stale-write failure

This commit is contained in:
cesnimda
2026-10-22 22:27:51 +02:00
parent 322b025350
commit 82be698dcf
69 changed files with 41364 additions and 1 deletions
@@ -0,0 +1,31 @@
# RD21 — Protect canonical Career and generic job edits from stale overwrites
**Severity: High. Status: reproduced / unresolved. Safety qualification: FAIL.** This is an existing risk carried from Phase 7, now reproduced with two independently authenticated local clients on isolated synthetic SQLite. The characterization test passing means the observations were captured; it does not mean writes are safe.
## Exact reproduction
1. Both clients read the same saved Career Profile, whose summary is “Initial summary”.
2. A changes the summary to “First editor committed summary” and receives 200.
3. B changes a different field in its old snapshot and submits it. B receives 200; a fresh read now contains “Initial summary”. A's acknowledged edit is lost.
4. Repeat with a saved job. A changes the title to “First editor committed title”. B changes notes in its stale full snapshot and receives 204. Readback restores “Original job title”.
Fresh [native evidence](rd21.json) records exact statuses/values. Reproducer: [data.spec.ts](../p9-05/diagnostics/data.spec.ts), retained under the 18-case Phase 9 diagnostic lane. Ownership is the same account in both clients; this demonstrates stale-write loss, not a cross-account disclosure. Existing foreign-account protections and CV/Dashboard revision tests remain separate.
## Responsible boundary and dependency
The existing `CareerProfileController.Put` and `CareerProfileService` save the current submitted profile without a caller-supplied revision comparison. The generic `JobApplicationsController` PUT likewise applies an old complete snapshot without a complete expected-version contract. `UpdatedAtUtc` by itself is not an atomic precondition. Do not copy the Dashboard version shape into unrelated domains without deciding the actual contract.
This is a cross-caller API/data contract change. The Phase 9 brief requires major architectural/contract work to become a separate issue. No partial client-only workaround, arbitrary retry, silent merge, data rewrite or weakening of existing assertions is included in QA.
Owner: backend/domain owner with the Career and Jobs frontend owners. Separate work must inventory canonical import/history/restoration, job forms/bulk/workspace/extension/automation callers and legacy API consumers; define compatibility, version creation, atomic conditional write and conflict semantics; retain canonical/CV/frozen document boundaries; and preserve recoverable drafts when rejected. The Career write and later Identity completion also need explicit transaction/partial-failure behavior.
## Required closure evidence
- Concurrent independent clients editing different and same fields cannot silently overwrite an acknowledged save.
- Actual owner-and-revision preconditions on the database write; simultaneous submissions and first saves are covered.
- SQLite and supported MariaDB runtime evidence, including constraints, held readers/writers and partial failure.
- Conflicts preserve drafts and offer explicit current-data review/reload; account switch and stale session fail closed.
- Imports, history restores, generic job updates, lifecycle/bulk operations and old callers follow the agreed compatibility contract.
- Complete affected regression, frozen document byte preservation and no unrelated Identity replay.
Creation-intent idempotency is another retained RD21 concern; these stale-write observations do not claim to test or solve it. Production and unqualified data-integrity acceptance remain withheld. Phase 10 must not remove compatibility paths while this contract is unresolved.