4.3 KiB
RD21 investigation (23 October 2026)
Status: repair and qualification in progress; this is not acceptance.
Original failure
The unchanged Phase 9 characterization was executed on the exact baseline
8e7e3f6387544e24082ebe2c107c0b868897959e. Both independently authenticated
editors read the same synthetic record. Editor A changes and successfully saves one field.
Editor B changes a different field in its older complete snapshot. B's request is accepted and
replaces A's field with its original value. Subsequent authenticated reads show the loss.
See original-reproduction.json. Career stale response: 200;
job stale response: 204. Both lostFirstEdit values are true. The characterization's one passing
test establishes that the unsafe behavior was reproduced; it is not a safety pass.
New native SQLite tests additionally query persisted rows through independent DbContexts
immediately after acknowledgement. The original job safety assertion failed because the stale
request returned NoContentResult instead of a conflict. Career safety tests failed because the
stale request returned success and because an injected Identity failure left canonical rows
committed despite the failure response. These are separate deterministic regression assertions.
Mechanisms
- Generic job PUT reads the current row, maps the client's complete replacement over it and calls SaveChanges. The request has no source revision; the entity has no concurrency token. A fresh request context therefore accepts an arbitrarily old snapshot. This is persisted data replacement, independently of client display state. The optional awaited summary generation also creates an interval between read and write; checking only at controller entry is unsafe.
- Career PUT and restore similarly lack an editor revision. The canonical service increments Version but does not compare the editor's version or use it as an EF concurrency token. Children and history are transactionally saved, then the transaction commits. The controller updates ApplicationUser.ProfileCvStructureJson/CvText afterward. Identity failure can leave canonical and legacy projections inconsistent despite a failed operation response.
- Career parse and reviewed import acceptance also call the canonical replacement service and update the projection/application metadata separately. They must participate in the same guard and transaction; fixing only manual PUT would leave alternate replacement paths open.
Directly related text writers
SQLite tests reproduce the same persisted replacement through cover-letter save and application
drafts: a first acknowledged First approved text becomes Stale snapshot text after a later
request from the stale editor. These routes replace fields also writable through the generic job
snapshot. They are included in the bounded repair. Cover-letter history alone does not reject
stale approval or keep the current approved text intact. Legacy tailored-CV text replacement is
also an application-owned snapshot writer and must fail closed without its source revision.
Client lifecycle
Career has an existing synchronous mutation guard and disables its editor while saving. Its error paths retain drafts, but it cannot detect another session's change without server revision data. The shared job dialog does not guard older GET responses, and remains editable/closable during PUT; a successful submitted snapshot can close a dialog containing later unsent edits. The frontend correction will preserve the revision belonging to each draft, block conflicting in-flight actions, reject old responses, and display recoverable conflicts without blind retry.
Provider limitation
The read-only rtk proxy docker info --format '{{json .ServerVersion}}' probe on 23 October
failed: dockerDesktopLinuxEngine named pipe does not exist. No daemon installation/restart was
attempted. MariaDB runtime qualification is outstanding; SQLite and provider script generation
cannot substitute for a MariaDB persistence/concurrency run.
Historical recovery
No evidence establishes recovery of edits already overwritten before this repair. Canonical history may contain a prior profile snapshot, but availability and user intent must be examined per record. No production database has been accessed and no historical recovery is claimed.