Skip to content

Add deployable CPU linear-scan backend - #2347

Open
philsippl wants to merge 24 commits into
mainfrom
codex/cpu-linear-scan
Open

Add deployable CPU linear-scan backend#2347
philsippl wants to merge 24 commits into
mainfrom
codex/cpu-linear-scan

Conversation

@philsippl

@philsippl philsippl commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the correctness baseline for a deployable ARM CPU exact-scan backend as a new iris-mpc-linear-scan target. It reuses the production Hawk request, MPC, persistence, and result pipeline, but replaces HNSW candidate search with the GPU actor's two-eye linear-scan semantics. Existing GPU and HNSW targets remain available and unchanged.

This PR deliberately contains the simple scan implementation: no cold-eye cache/prefetch layer and no mixed-plane, fused mirror, NEON/UMMLA, or dot/MPC pipeline optimizations.

Depends on worldcoin/ampc-common#138; all four AMPC crates are pinned to fa95ff78a91ef3cfb3c8020afab0e50eae0dc88a.

Behavior and correctness

  • Loads one configured eye for the process lifetime and performs an exact 31-rotation scan in 4,096-record chunks.
  • Checks the second eye only for first-eye matches and known LUC/OR-rule/reauth candidates, matching the GPU cascade.
  • Enforces SMPC__MAX_BATCH_SIZE=1; the resident eye changes only on a coordinated restart through SMPC__FULL_SCAN_SIDE.
  • Preserves enroll, duplicate, mirror, deletion, reauth, reset/recovery, retained distance-share, and result-persistence behavior.
  • Uses exact database versions for cold-eye reads and fails the request closed on a missing row instead of substituting zero shares.
  • Keeps database and in-memory version advancement consistent for idempotent iris updates and safely handles hidden partial results.

CPU/GPU equivalence was checked on 3 × A40 for public results and retained distance shares. A deterministic 100-request full-server sequence covering enroll, duplicate, mirror, deletion, reauth, reset, and recovery also produced identical canonical CPU/GPU result files with a 5,000-record database, larger than one CPU scan chunk.

Validation

  • cargo check -p iris-mpc-bins --bin iris-mpc-linear-scan
  • cargo clippy -p iris-mpc-cpu -p iris-mpc -p iris-mpc-bins --all-targets -- -D warnings
  • Linear-scan search tests: 6 passed.
  • Result-shaping and server configuration tests: 4 passed.
  • DB-backed cold-eye integration test compiles with db_dependent.

Deployment note

The additive binary, image workflow, and stage/prod manifests are introduced here, but production should deploy the complete stack through #2348. Do not run GPU and CPU consumers against the shared queues simultaneously; drain all three GPU consumers, then roll all three CPU parties together with the same full-scan side.

Review guide

  1. Start with the additive entry point in iris-mpc-bins/bin/iris-mpc/server/iris_mpc_linear_scan.rs and mode selection in iris-mpc/src/server/mod.rs.
  2. Review the two-eye cascade and chunk result assembly in iris-mpc-cpu/src/execution/hawk_main/search.rs.
  3. Review one-eye initialization and exact cold-eye loading in worker_pool_initializer.rs and iris_worker.rs.
  4. Finish with the GPU parity, CPU E2E, LocalStack, and native ground-truth tests.

Stack

Comment thread .github/workflows/build-and-push-linear-scan-server.yaml Outdated
@philsippl

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@carlomazzaferro

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57025e7775

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread iris-mpc/src/services/processors/job.rs Outdated
Comment thread iris-mpc-utils/src/client/options/types.rs Outdated
Comment thread iris-mpc-cpu/src/execution/hawk_main/test_utils.rs Outdated
Comment thread iris-mpc/src/server/mod.rs Outdated
Comment thread iris-mpc-cpu/src/execution/hawk_main/iris_worker.rs Outdated
Comment thread iris-mpc-cpu/src/execution/hawk_main/iris_worker.rs Outdated
Comment thread iris-mpc-cpu/src/execution/hawk_main/iris_worker.rs
return Ok(ids
.iter()
.map(|id| store.get_vector_or_empty(id).clone())
.collect());

@dkales dkales Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just thinking: Since this is behind a trait anyways can the cold-storage one not be a completely new struct, maybe wrapping the old worker pool, instead of doing a lot of selecting based on this option here?
(This was about the Option<ColdStorage>) in the worker)

Comment on lines +311 to +326
}

tracing::info!(
eye = %second_eye_side,
orientation = orientation_label(orientation),
requests = n_requests,
candidates = candidate_count,
"Running candidate-only linear-scan stage"
);
metrics::counter!("linear_scan_second_eye_candidates_total").increment(candidate_count as u64);
let second_results = linear_scan_eye(
sessions,
search_queries,
&search_params,
LinearScanEyeContext {
eye: second_eye_side,

@dkales dkales Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably does not take too long but this is the whole DB id set, right? Maybe the registries can just keep this around themselves instead of computing it here fresh?
(This was about the live_id creation block in linear_search_cascade)

@github-actions github-actions Bot added the chore label Aug 20, 2026
Persistence
- Startup modification replay advances version_id explicitly for
  reauth/identity-update/deletion rows, matching live persistence. The
  content-sensitive trigger left a replaying node one version behind its
  peers for idempotent writes (dummy -> dummy deletions, identical reset
  shares), which diverges registry set hashes and fails cold-eye
  exact-version reads closed.
- update_iris_and_increment_version reports a missing row instead of
  bailing; process_job_result logs and counts it rather than exiting all
  parties on one out-of-range serial id.

Linear-scan matching
- Resolve the matching module's other-eye comparisons from the cascade
  results instead of a second is_match_batch pass. Every requested id was
  already evaluated on both eyes (strict matches are a subset of the
  anon-stats prefilter; LUC/OR-rule/reauth ids are unioned into the
  candidate stage), so this removes per-rotation cold-eye database reads
  from the MPC critical path and a second, different threshold circuit.
- Cap match_ids and full_face_mirror_match_ids like the partial lists
  (CUDA reports at most ALL_MATCHES_LEN per device).
- Apply the supermatch threshold only when return_partial_results is set,
  as the CUDA actor's match counters stay zero otherwise.
- Reject SMPC__FULL_SCAN_SIDE_SWITCHING_ENABLED=true in linear-scan mode
  instead of silently ignoring it.

HNSW/GPU scope
- Keep HNSW anon-stats recording for skip_persistence requests; only the
  linear-scan backend mirrors the CUDA behavior.
- Restore tolerant cuMemHostRegister handling in the GPU actor, logging a
  warning instead of panicking at startup.

Cleanup
- Remove the unreachable linear-scan branch from per_session; matching
  scans must use linear_scan_cascade.
- Share one implementation across the from_cli* test constructors.
- Drop the copied clippy allow from the new binary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAbAnQyfsSrWH6UGcRM1FF
Comment thread iris-mpc-cpu/src/execution/hawk_main/worker_pool_initializer.rs
Comment thread iris-mpc-cpu/src/hawkers/aby3/aby3_store.rs Outdated
philsippl and others added 3 commits August 21, 2026 11:52
- Cache the serial-ordered live VectorId list in SharedIrises, dropped by
  every mutation, and have linear_scan_cascade take it from the registry
  instead of re-enumerating millions of points per scan. All requests,
  sessions, and orientations of a batch now share one allocation.
- full_rotation_dot_shares no longer demands DistanceMode::MinRotation:
  the exact scan is neither distance mode, it opens each of the 31
  rotations separately. Keep the check that actually matters, that the
  query is the center rotation of the Hawk query layout.
- In cold mode the non-resident registry is a copy of the resident one,
  so log a single resident checksum instead of two identical values that
  look like an independent check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAbAnQyfsSrWH6UGcRM1FF
worldcoin/ampc-common#138 merged; a0b968c4 was its pre-merge head and is
not an ancestor of ampc-common main. Pin 11bcd059, the current main head,
which also carries the #140 threshold-path allocation reductions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAbAnQyfsSrWH6UGcRM1FF
A fresh Cargo.lock hash (the ampc-common re-pin) makes the release build
consume most of the old budgets; unit-tests was then cancelled during
its cache upload, keeping every later run cold, and the integration
tests were cancelled mid-run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAbAnQyfsSrWH6UGcRM1FF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants