# Backend repair contract (mandatory for all repair workers) Prior broad edits introduced cascading signature errors. Parent stopped the old backend process. Repair in narrow file ownership; other workers may be editing their own files. Do NOT edit outside your allocation. Do not weaken tests, delete API handlers, or change language/framework. ## Fixed signatures - state.rs exports `pub type Cx = axum::extract::State>;` - AppState owns cfg:Config, db:tokio::sync::Mutex, run_sem/fetch_sem Arc (preserve other needed state). - `impl AppState { pub async fn with_db(&self, f: impl FnOnce(&mut rusqlite::Connection) -> R) -> R { let mut db = self.db.lock().await; f(&mut db) } }`. - This returns exactly R after await. If closure returns Result, use `.await?`; if closure returns number/unit, `.await` only. Never await inside database closure. Keep transactions and atomic operations inside ONE closure. No nested locks. - Handler argument is `cx: Cx` (State extractor), not a bare Arc alias. Helper taking `&Cx` receives `&cx`. Background jobs may use Arc and create `State(cx.clone())` only where necessary. All handlers futures must be Send. - util::now_iso() -> String is SYNCHRONOUS. hash/random token helpers synchronous unless they actually await. - error::AppError supports new(StatusCode,code,message), bad(code,message), unauthorized(message), forbidden(message), not_found(message), conflict(code,message), internal(message), with_details(Value), with_code(code). One inherent impl, one IntoResponse, one From, one From, one From. Never duplicate From impl elsewhere. - `auth::make_admin_token` existing admin call sites need coherent async Result signature; auth/admin worker owns both. - Router Axum0.8 paths use `{id}`, NEVER `:id` (runtime panic). - Do not change actual JSON HTTP contract: SPEC.md + RELEASE_SCOPE.md authoritative. ## Worker partition CORE: config.rs state.rs error.rs util.rs main.rs store.rs worker.rs Cargo.toml (+ core tests). Main integrates call signatures but not other module sources. AUTH: auth.rs admin.rs (+ auth tests inside module). DOMAIN: projects.rs datasets.rs runs.rs ai.rs jobs.rs (+ domain tests inside module). Read other files freely. Compile often, filter diagnostics for OWN modules; leave other-worker diagnostics alone. Final shared compile gate performed by parent. ## Parent findings to address - main.rs origin substring match is exploitable. Compare exact canonical origin (scheme+host+port), reject `https://allowed.example.evil.invalid`. Empty canonical allows exact local origin only. No trust of X-Forwarded host. - Serve frontend/dist static SPA with index.html fallback for UI only; /api unknown returns JSON 404 (not SPA). - Instrument search current stub must connect to actual worker catalog command; no fake successful empty list. Docker worker fetch/search with bounded time and resource. - Concurrent fetch duplicate cache key must serialize/recheck. request/cache key and manifest hash are distinct columns/concepts. - All raw+normalized referenced artifacts retained; worker manifest fields must be checked against live worker code. - Read-only nonroot container UID65534 needs writable output (parent job dir0700, output mode0777 inside; no secrets). Input/data are read-only. Stdout/stderr bounded and drained; timeout/cancel container cleanup real. - Finished run state only succeeded if worker JSON status says succeeded. Failed/cancelled state must not be overwritten by racing completion. - Durable queued jobs recheck account active, dataset ownership/readiness, per-user budget. - Invitation email binding, one-time transaction, no role escalation; disable/reset revoke sessions; last admin protection. Parent independent API tests live at scripts/qa_api.py, including substring CSRF and admin/private owner separation. READ these gates and make them genuinely pass. Parent prepares isolated QA environment, do not read any secrets outside project.