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.
+15
View File
@@ -0,0 +1,15 @@
# P9-04 — Data integrity, providers and security
**PARTIAL overall; RD21 stale-write safety FAIL; MariaDB runtime NOT TESTED.** These dispositions are independent from passing security guards and CV/Dashboard revision contracts.
The complete backend run passed **1,084/1,084**, no failures/skips, on unchanged backend source. [Exact per-case results](../p9-00/backend-cases.json) retain migration-chain/startup/schema ownership, SQLite WAL/held-reader/parallel writes, dashboard owner-and-revision comparisons, unsafe/future-schema/body-limit guards, CV revision/restore, account isolation, session revocation/context/CSRF, admin/last-admin/self guards, document ownership, attachment validation, import URL/transport protections, account export/deletion and sidecar admission contracts. Test-host authentication and SQLite are identified as such; test names do not certify a deployed endpoint.
The 33-route native identity census and separate AI, auth-recovery, rate-limit, ingress and PDF admission lanes belong to the final regression record. Their actual completed counts, rather than expected baseline totals, determine acceptance. Ordinary browser cookies/session context/CSRF exercise local HTTP; local SMTP and inert PDF/AI fixtures are not external-provider/model/native-output acceptance.
The new two-client [RD21 observation](rd21.json) reproduces loss of acknowledged Career and generic job edits. Both stale requests are accepted (200/204) and restore old fields. [Separate issue and exact reproduction](RD21_CONCURRENCY_ISSUE.md) define affected callers and closure proof. CV/Dashboard conflict rejection does not close this. Creation-intent idempotency and the canonical-write/later-Identity partial-commit concern remain separate uncompleted requirements.
Provider availability was checked without installing/restarting services: Docker fails to connect to `dockerDesktopLinuxEngine`; `mariadbd`/`mysqld` are absent from PATH. The existing MariaDB SQL-generation case passes, but no MariaDB server ran. Actual provider startup/migrations/CRUD/constraints/concurrency/restart therefore remain NOT TESTED. No live database, production migration, schema cutover or destructive reset was used.
Offline security gates passed: tracked-secret scan, supply-chain helpers 3, Ollama evaluation helpers 5, browser-runtime helpers 6, ingress helpers 3, Node dependency-policy/SMTP contracts 15 and extension URL contracts 3; SBOM generated from the lockfiles. Exact command exit codes/log hashes are retained in `validation.json` / `.artifacts/phase9/offline.json`. These are bounded tests/static checks, not a penetration-test or blanket security certification.
No manifests, lockfiles, database models/migrations, auth grants, upload limits or inference configuration changed. Live advisories, real provider grants/delivery, enabled-worker recovery, deployment ingress, retention policy, restore/rollback and actual release identity remain [open gates](../RISKS.md). No live external content or model inference was fetched to replace missing evidence.
+21
View File
@@ -0,0 +1,21 @@
{
"id": "RD21",
"career": {
"staleStatus": 200,
"expectedFirstSummary": [
"First editor committed summary"
],
"actualSummary": [
"Initial summary"
],
"lostFirstEdit": true
},
"job": {
"staleStatus": 204,
"expectedFirstTitle": "First editor committed title",
"actualTitle": "Original job title",
"lostFirstEdit": true
},
"safetyQualification": "FAIL: stale writes can overwrite acknowledged edits",
"limitation": "This passing characterization records observed behavior; it does not accept unsafe stale writes or provide a new revision contract. Creation-intent idempotency remains separate."
}