Implement B01-B06 with regression coverage and retained validation evidence. Preserve the production ingress preflight; F04 runtime verification remains open.
27 KiB
Resilience, partial failure and the 50 failure answers
Source baseline, labels and limitations: README. Findings: F01–F21. “Needs runtime verification” means the scenario was not executed, even when source provides a strong prediction.
Dependency and operation failure matrix
Timeouts marked current come from source; operational alert thresholds are proposals. Normal CRUD should remain useful during optional-provider failures.
| Dependency / operation | Failure and user impact | Current timeout / retry | Recovery and target UX | Alert / evidence |
|---|---|---|---|---|
| SQLite / MariaDB | Writes, auth/session checks and reads fail; active AI worker can stop host F20 | Provider defaults; observed SQLite command timeout 30s; no central transient-DB policy | Preserve forms, show service unavailable/reference; bounded worker recovery; never retry ambiguous writes without key | Readiness failures + sustained DB errors; real outage needs runtime verification |
| AI sidecar | AI/extraction fails while manual work should continue | API named client 30s; classified queue failures retry within deadline | Persistent operation status and safe retry; synchronous edits remain unsent until reviewed | Task/provider failure rate and pending age; fake-provider tests passed |
| Ollama / external AI | Missing model, DNS/HTTP failure, malformed result | Per-task/provider routing; durable default 3 attempts / 15min deadline, worker timeout 300s | Explicit failure or policy-approved fallback; never silently send private content externally | Model/task/version/category counters; live model evaluation not performed |
| Parser | Malformed/hostile/oversized input, child timeout | 5MB file; 25s child, 512MiB configured child memory, one parser at a time; container 2GiB/2CPU | Stable error, review/import can retry, previous profile retained | Parser crash/timeout/rejection counts; 37 parser tests passed; container enforcement not exercised |
| Chromium PDF | Missing executable/crash/timeout, partial output | 60s process timeout; no shared admission | Retain CV; explain download failed; retry only after cleanup/lookup; F03 bounds required | Active process/RSS/timeouts/files; no heavy live stress test |
| SMTP | Verification/reminder send fails or is suppressed | Configured timeout (dev 15s), synchronous send in Task.Run; direct auth/reminder attempts | Outbox/attempt state; do not mark suppressed as delivered; resend verification within token validity | Queue age/send failures/bounces; actual delivery not tested |
| Gmail / Graph / IMAP | Mail sync/calendar/send unavailable, revoked credentials | Provider-specific paths; send attempts preserve uncertain status | Manual tracking usable; reconnect action; do not auto-resend uncertain employer mail | Last sync success, auth/provider error, unresolved send attempt |
| Stripe | Checkout/portal unavailable; delayed webhooks, role mismatch | SDK calls; failed webhook returns non-2xx | Preserve current local state pending authoritative reconciliation; status banner; deletion waits for cancellation | Inbox age/divergence/cancel failures; sandbox required |
| Job site / NAV / translation | URL unavailable, oversized response, DNS fail | Job import client; redirects rejected, 4MB stream cap | Allow manual paste/edit; no empty replacement of a valid job | Timeouts/rejections/cache hit; real sites not called |
| File storage | Permission, missing bytes, full disk | I/O exceptions; staged attachment recovery; no universal quota | Roll back or preserve recoverable stage; do not create valid-looking broken artifact | Disk/inode pressure, orphan/missing counters, failed purge |
| Proxy / DNS / TLS | Site unreachable despite live backend | External infrastructure unknown | Correct route/cert/DNS, verify from outside; static maintenance response if necessary | External probe independent of host; not inspected live |
| Browser network | Offline/delayed/partial save/download | Axios has no shared timeout; no blanket retry; many local async handlers | Keep dirty state, bounded deadlines, retry by operation identity; distinguish ambiguous outcome | UI safe errors and request references; offline CV probe observed failure state |
| Logging / telemetry | Sink unavailable, disk growth, blocked script | Console logging; client errors best-effort | Drop/sample bounded optional telemetry; never block saves on a collector | Local dropped-event counter, disk alerts; failure injection pending |
| Backups / off-site copy | Missing/partial/inconsistent set | Script checks artifact shape; defaults 30 daily days/12 monthly sets | Preserve previous verified set; restore drill; do not prune based on unverified success | Backup failure and age from independent monitor; restore pending |
| Redis / broker / standalone document service | Not present | Not applicable | Do not add failure domains without a measured requirement | Reassess if introduced |
Transaction and background-work review
| Workflow | Existing transaction / state design | Partial failure that matters | Minimum change |
|---|---|---|---|
| Create CV + version 1 | Two saves inside a relational transaction | Concurrent later edits still lack preconditions | Preserve creation transaction; add F01 |
| Career Profile save | Relational children/profile/history transaction; controller later updates user projection | Canonical data committed but legacy projection/user update fails | One commit if same DB context can own all writes, or explicit repairable projection; do not tell user total failure after success |
| Job create/status | Job/opportunity/history saved together in normal EF unit | Client loses response and resubmits; no creation intent key | Return/retrieve result by idempotency key |
| Attachment upload/delete | Stage/quarantine files; DB commit; promote/purge; startup reconciliation | Commit uncertainty or crash leaves metadata/file transitions pending | Preserve existing protocol, add aggregate quota reservation and missing-file alert |
| Submitted package capture | Renders/reads before DB transaction; copies files during transaction; unique package version | Concurrent max-version selection collides; source can change during capture; cleanup race | Allocate package revision safely, use unique attempt storage then publish; freeze source revisions; test file ownership of cleanup |
| AI operation | Durable owner/idempotency/lease/deadline, result reference and attempts | Provider succeeds but result commit fails; worker crashes | Result persistence idempotency and lease recovery; F20 loop recovery; classify poison failures as terminal |
| Employer send | Durable attempt and payload hash; uncertain state preserved | Provider accepted send but response/DB completion lost | Reconcile by provider message ID when possible; explicit user decision before retry |
| Reminder / verification email | Direct send; reminder timestamps committed after loop | Duplicate/suppressed/unrecorded send F07 | Durable intent/attempt ledger; SMTP cannot guarantee exactly-once |
| Stripe webhook | Re-fetch then user update then role mutation | Partial role update; overlapping subscription events | Per-customer transactional reconciliation + durable inbox |
| Account deletion | Persist stages; revoke sessions/share, quarantine, delete rows, purge, tombstone | In-flight files/results after inventory; Stripe still active; crash replay | F02 cancellation stage; coordinate active work and final inventory; exercise restore tombstones |
| Export | Account ZIP on disk; table JSON buffers; delete-on-close stream | Crash leaves ZIP; changes during export can span different logical moments | Consistency semantics/manifest; stale file cleanup; bound memory or background export |
A transactional outbox is justified for required transactional mail and local billing work because an external side effect cannot join the database commit. It is not a reason to wrap every CRUD handler in infrastructure. Keep APIs/providers outside long DB transactions. Retries need operation identity, a payload hash and a known outcome; GET that triggers AI or writes should be examined before treating all GETs as harmless retry candidates.
Resilience test matrix / Break Jobjakt
| Scenario | Test method | Expected behavior | Current result | Fix / next evidence |
|---|---|---|---|---|
| Two tabs save same CV | Read once, sequential stale PUTs; concurrent PUT pair | Conflict; newer state preserved | Observed fail: 200/200, stale state replaced newer edit | F01; extend to job/profile/restore |
| Duplicate create / Save double-click | Two identical job POSTs | Same intended action returns one resource | Observed: two 201s, distinct IDs | Introduce explicit intent-key contract; do not block legitimate repeat applications |
| Other user's CV IDs | Direct GET/PUT/DELETE as account B | 403/404, no mutation | Observed pass: all 404 | Keep permanent owner tests |
| Ordinary user admin call | GET admin audit | 403 | Observed pass: 403 | Extend all admin verbs |
| Same-IP account export | A exports twice, B exports once | Independent account limits | Observed fail: B gets 429 | F06 middleware integration test |
| Formula/Unicode/HTML input | Create synthetic job =1+1, Åse/company emoji, HTML note; export |
Store safely, safe spreadsheet cells | Observed: storage works; formula preserved unsafe in CSV | F05; full stored-XSS surface still runtime needed |
| Offset/DST calendar | Four input instants through DB to ICS | Preserve UTC instant; repeated autumn hour distinct | Observed fail: all four return wrong UTC values, HTTP 200 | F21; both database/server-zone matrices |
| Offline CV save | Browser context offline during name edit | Failure shown; no false saved state | Observed pass: failure message present | Preserve visible state |
| Refresh after failed save | Accept unload warning, reload | Recoverable draft if recovery supported | Observed gap: draft not recovered | F09; warning exists, recovery does not |
| Logout in second tab | Shared-cookie logout + auth-marker event | Clear private UI; deny future requests | Observed gap: other editor remains mounted | F08; distinguish visual residue from backend denial |
| EN/NB, light/dark, 375/1440 | Static build + Chromium + axe + screenshots | No serious violations/overflow | Observed: outer overflow 0; contrast errors all 8 states; desktop scroll-focus errors | F14; manual assistive tech still needed |
| Malformed PDF/DOCX, ZIP bomb, parser hang | Existing pytest mocked/isolated child suite | Bounded rejection, no secret inheritance | Observed: 37 tests pass; not a live malware corpus | Run container boundary/fuzz corpus in disposable environment |
| DB down 30s / 1h | Disconnect disposable MariaDB or fault-inject repository | Bounded errors, live host, retry recovery | Needs runtime verification; F20 predicts host risk with AI worker | Add loop failure test then staging drill |
| Container restart mid-write/generation | Kill only a disposable deployment after known checkpoints | Durable work resumes; ambiguous writes recover | Needs runtime verification; unit lease/recovery tests pass | Exercise actual process/files/DB recovery, not mocks alone |
| API latency/timeout/partial response | Local reverse proxy delays/truncates selected responses | Dirty state kept; no blind POST retry | Needs runtime verification | Test stale search replies, file upload/download, proxy deadline |
| Browser storage corrupt/denied | Invalid JSON/unknown schema + throw on storage APIs | Safe defaults and retained form | Unit owner/theme tests pass; full route sweep Needs runtime verification | I18n reads/writes need denied-storage coverage |
| Screen reader/keyboard/200–400% zoom | Narrator/NVDA + actual browser zoom + text-spacing | Reach all controls, focus/announcements, usable reflow | Needs runtime verification beyond existing keyboard tests/axe | Do not equate viewport width or axe with screen-reader proof |
| PDF 1000 simultaneous / 100k jobs | Synthetic capped load/fake renderer first | Global admission, bounded queries/memory | Needs runtime verification, source gaps F03/F10 | Never execute uncapped exhaustion on shared host |
| Disk/inodes/RSS exhaustion | Quota-mounted temp volumes/cgroup-limited staging | Fail before corruption; alert/recover | Needs runtime verification | Preserve backups; no filling the user's actual disk |
| Billing/mailer/OAuth outage | Fake gateways then sandbox provider callbacks | Correct pending/failed/retry state | Fake-gateway suites pass; live integrations Need runtime verification | F02/F07 and provider-specific contract tests |
| Backup corrupt/missing / migration halfway | Restore isolated backup, interrupt test migration | Fail deploy or forward-recover to a known checkpoint | Needs runtime verification beyond current migration/unit tests | F12 and signed drill record |
The harness is observational: meetsExpectation=false records an unmet desired control, not a flaky test that should be retried until green. No PDF/CPU flood, actual malicious executable, payment, employer email or production outage was attempted. Logs distinguish deliberate offline/401/blocked-font errors from normal workflow errors. Full packet-loss simulation, clean-machine setup, production network/console/log cleanliness and exhaustive UI state testing are outstanding, not implied by this matrix.
What happens if…?
| # | Scenario | Current answer and evidence boundary |
|---|---|---|
| 1 | Database offline for 30 seconds | Reads/writes and DB-backed session checks fail. /health is process-only; /ready checks DB. Enabled AI-worker claim/persist errors can stop the host F20. Forms need recoverable failure UX. Source; Needs runtime verification. |
| 2 | Database offline for an hour | No offline DB mode. Requests continue failing, leases age, worker/host restart behavior may recur; recovery requires DB availability and operation reconciliation. Alert early, preserve accepted work. Needs runtime verification. |
| 3 | Docker host restarts | Named DB/file/key/tombstone volumes should survive; unless-stopped services restart. In-memory caches/limits reset; durable leases recover. External MariaDB/proxy start order still matters. Needs runtime verification. |
| 4 | API dies halfway through request | Uncommitted DB transactions roll back; completed commits can be invisible to client. Staged attachments have recovery logic; synchronous PDF/email may be ambiguous or leave residue. Retry by operation ID, not blindly. Source; Needs runtime verification. |
| 5 | Frontend older than backend | Current unversioned DTOs have no negotiated compatibility/reload protocol. Additive changes usually survive; required/removed fields and enum changes can break open tabs. No automatic safe update guarantee. Needs runtime verification. |
| 6 | Migration fails halfway through deployment | Startup migration/reconciliation may prevent readiness; provider DDL rollback differs. Image rollback cannot unapply schema. Abort, preserve logs/checkpoint, determine forward fix versus isolated restore. Needs runtime verification. |
| 7 | Disk reaches 100% | DB/file/log/backup writes can fail; current API has no universal headroom admission policy. Staging helps attachment consistency, not host capacity. Stop costly admission and recover space safely. Needs runtime verification. |
| 8 | Memory exhausted | OS/container can kill API/renderer; normal process lifetime assumptions fail. Sidecar is constrained, API/PDF not globally bounded. F03/F10 apply. Needs runtime verification. |
| 9 | AI requests time out | Named client has 30s timeout; durable jobs classify/retry within deadlines, synchronous callers return failure/fallback. Manual data should remain usable. Fake timeout tests pass; live provider recovery Needs runtime verification. |
| 10 | Selected AI model removed | Configured route fails; privacy-approved fallback may apply. No evidence justifies silently choosing arbitrary replacement. Pin evaluated model and show retriable/unavailable state. Source; Needs runtime verification. |
| 11 | Email provider unavailable | Direct auth/reminder sends fail; some account changes already commit. Employer-send attempts can retain failed/uncertain state. Verification resend is necessary; outbox gap F07. Needs runtime verification. |
| 12 | Verification never delivered | User remains unverified where verification required; can request resend, subject to rate limits. No delivery guarantee, bounce proof or durable resend queue shown. Provide clear support/recovery path. Source; Needs runtime verification. |
| 13 | Stripe sends same webhook five times | Signature verified; each request re-fetches current subscription and reapplies roles. Sequential final state is generally idempotent; redundant work and concurrent writes remain. Handler does not charge five times. Source; sandbox Needs runtime verification. |
| 14 | Stripe events out of order | Current re-fetch mitigates sequential stale payloads. Concurrent handlers and multiple subscriptions can still conflict; no serialized customer reconciliation. F02. Source; Needs runtime verification. |
| 15 | Double-click Save | CV single-editor save queue serializes local changes; API does not dedup generic creation. Observed: identical job POSTs returned two IDs. A UI disabled button alone is insufficient. |
| 16 | Two tabs save same CV | Observed: stale and simultaneous PUTs both succeed; newer data can be overwritten. History is not conflict prevention. F01. |
| 17 | Refresh during CV generation | Queued extraction/AI can survive through operation records; synchronous preview/PDF request may abort/continue without recoverable browser result. Unsaved client state may be lost. Source; Needs runtime verification for generation refresh. |
| 18 | Session expires while editing | First 401 clears client auth and re-fetches identity; long-form state can unmount. No complete reauthentication-and-draft recovery contract found. Offline/unload warning behavior was tested separately. Needs runtime verification for actual expiry. |
| 19 | Logout in another tab | Observed: idle private CV editor stays mounted in the other tab. Backend session is revoked and subsequent requests fail. F08. |
| 20 | Delete CV referenced by application | Variant/history removed; job itself is not owned by CV. Already captured submitted package retains rendered content/copied bytes. Live selected-variant UI must handle missing resource. Source and package tests; exact multi-tab deletion Needs runtime verification. |
| 21 | Malformed PDF | Parser/upload bounds reject invalid data or return stable extraction failure; profile should not be replaced with invalid output. Observed existing parser tests pass; broader parser fuzzing remains. |
| 22 | Malicious uploaded document | Type/expansion/process limits reduce parser risk; no complete malware-scanning/quarantine-verdict service was found. Original download still requires safe headers. Source; real malware execution not performed. Needs runtime verification of container isolation. |
| 23 | Job URL redirects to localhost | Import HttpClient disallows auto-redirect; fetch rejects 3xx. Redirect is not followed. Source and importer tests. DNS rebinding is a separate remaining risk F11. |
| 24 | Job description contains prompt injection | It is untrusted prompt data; policy and review limit actions, but wording alone does not guarantee model obedience. No provider/network tools should be granted from model output. Synthetic eval fixtures exist; live adversarial model behavior Needs runtime verification. |
| 25 | AI returns invalid JSON | Parsing/normalization boundaries can return failure/fallback; durable status records category. Exact all-workload behavior is not proven by one parser. Source/fake-provider tests; full contract corpus Needs runtime verification. |
| 26 | AI invents experience | Reviewable suggestions and fact-preservation prompts exist; they cannot guarantee truth. Reject unsupported structured claims and require user review before export/send. Live English/Bokmål semantic evaluation Needs runtime verification. |
| 27 | 1000 users request PDFs | No shared admission: many Chromium processes could exhaust API host. Per-public-IP+slug throttling does not bound aggregate authenticated load. Source F03; intentionally not stress executed. Needs runtime verification after bounding. |
| 28 | One user creates 100k jobs | Creation lacks total row quota; list pagination does not bound board/analytics/export scans. Expect latency/memory growth, not demonstrated capacity. Source F10; Needs runtime verification with synthetic data. |
| 29 | Export extremely large | ZIP file output is streamed on download, but generation loads collections/serialized buffers; jobs export materializes all rows. Can exhaust memory/disk or time out. Source; Needs runtime verification. |
| 30 | Quota reached during operation | AI reserves estimates before work; actual final usage may differ. Attachment check-before-write is racy and excludes other file categories. Need reservation/reconciliation and retained inputs. Source/unit tests; cross-pipeline load Needs runtime verification. |
| 31 | Subscription expires while logged in | Pro policy reads current DB roles and queued workers recheck; UI may remain stale until re-fetch. Correctness depends on billing sync updating roles. Source/entitlement tests; delayed-provider event Needs runtime verification. |
| 32 | Account deletion with pending work | Staged deletion revokes sessions/shares and cancels/removes owner work, purges files and records tombstone. In-flight external effects/billing require coordination F02. Source/deletion tests; concurrent runtime drill needed. |
| 33 | Backups silently fail seven days | File-age/catch-up logic exists locally and scheduled production workflow exists, but an independent delivered alert was not proven. Operator could remain unaware. Gate on independently measured backup age. Needs runtime verification. |
| 34 | Latest backup corrupt | Shape checks can miss logical corruption. Restore previous independently verified set and establish lost interval; do not overwrite live state before validation. Needs runtime verification F12. |
| 35 | TLS certificate expires | Browsers block/warn before application loads; backend health can remain green. Renewal belongs to external proxy operator. Independent certificate/HTTPS alert required. Needs runtime verification. |
| 36 | DNS breaks | Users/provider lookups fail before API workflows; cached clients may behave differently. Check authoritative and recursive resolution separately from health. Needs runtime verification. |
| 37 | Production secret leaked | Scope depends on JWT/provider/DB/CI/key material. Revoke/rotate and invalidate affected sessions/tokens; preserve evidence and identify exposed data. Key-ring rotation must preserve/re-encrypt required secrets. Runbook proposal; Needs runtime verification. |
| 38 | Administrator compromised | Can mutate users/roles and read global activity metadata/content; host admin reaches DB/files/keys. Minimal support access and audited privileged reauth are incomplete F13. Source; no live compromise simulated. |
| 39 | Another container compromised | Shared-network access can reach attached services; isolated AI network is helpful, but backend shares several networks and has high privileges. Actual firewall/volume/socket exposure Needs runtime verification. |
| 40 | Attacker requests another user's resource ID | Observed CV GET/PUT/DELETE 404 and admin 403; 753-test suite includes broader owner tests. This does not prove every future/new route; maintain route inventory/owner regression gate. |
| 41 | Browser cache contains previous user's data | Owner-scoped caches exist, but cross-tab UI residue and absent no-store remain. No cross-user HTTP cache exploit was demonstrated. Source/partial observed; complete Back/cache account-switch test Needs runtime verification. |
| 42 | localStorage corrupt | Theme/auth helpers catch many failures, jobColumns JSON is guarded; language storage and some writes are less defensive. Manual modifications never grant backend roles. Full corrupt/blocked-storage route sweep Needs runtime verification. |
| 43 | JavaScript error mid-form | Error boundaries can display fallback/reference, but local form state may be lost on remount. Test recoverable draft behavior and safe telemetry; no guaranteed content preservation. Source; Needs runtime verification. |
| 44 | 200% zoom | Responsive layouts and tested narrow viewports help; actual browser zoom was not exercised. Needs runtime verification. Do not equate 375px viewport with zoom certification. |
| 45 | Keyboard only | Existing browser flows exercise selected buttons/navigation. New builder axe finds a scrolling-region focus issue; full tab/escape/reorder/return-focus journey remains. Partial observed; manual verification needed. |
| 46 | Screen reader | No live Narrator/NVDA run. Axe flags do not establish reading order, announcements or accessible generated PDFs. Needs runtime verification. |
| 47 | Norwegian text twice English length | Actual EN/NB builder states showed outer overflow 0 at 375/1440; not a doubled-string pseudolocale sweep. English template descriptions remain in NB. Partial observed; pseudolocale/all-route verification needed. |
| 48 | Hundreds-character company/job title | Normal browser suite has long-content workspace/CV cases and passed. Arbitrarily large inputs/100k rows are not covered; cap fields and test wrap/reflow. Partial observed; extreme boundaries need runtime verification. |
| 49 | Emoji/unusual Unicode | Observed: Åse/company emoji and profile content survive synthetic storage/render. Full combining/RTL/confusable corpus and generated glyphs need verification. |
| 50 | Paste formatted HTML | Plain inputs store text; React escaping/renderer encoding are intended barriers. Harness stored an HTML note but did not certify every rendering/email/Markdown sink. No rich-text sanitizer should be replaced by regex. Source/partial observed; persistent-XSS/paste corpus Needs runtime verification. |
Time and compatibility policy
F21's four live HTTP/SQLite/ICS failures are concrete; the fix must distinguish calendar date, absolute instant, and local recurring time with timezone. Current use of DateTime, UTC timestamps and server-local reminders mixes those meanings. UTC is suitable for security events and leases. Date-only job deadlines must not shift with timezone. Recurring wall-clock behavior, if offered, needs an explicit zone and gap/fold policy. Do not add recurring reminders merely to justify a scheduling platform.
The production backup workflow checks for 02:00 Europe/Oslo at two UTC schedules. A spring-forward day has no 02:00 local hour; a fall-back day repeats it. Add a date-based idempotency/catch-up test rather than assuming the guard yields exactly one daily backup. Scheduler DST behavior was source-reviewed, not executed in Gitea.
Adopt expand/contract for externally visible DTO/schema changes: optional fields and readers first, dual-compatible writer period, measured old-client window, then removal. Keep stable IDs/routes and old enum meanings. Introduce explicit API versioning only when real independent clients require it. Build/version metadata already exists; a safe reload prompt may help, but must not discard dirty forms. Old-image compatibility is a precondition to automated rollback, not an assumption.