B02 Plan B: split Groth16 verifier into @zeroauth/verifier workspace#29
Merged
Conversation
Per the plan-mode design doc, this is Plan B (TypeScript workspace, not
Rust) — chosen for single-engineer velocity. The HTTP shape is
Rust-compatible so a future swap is structural, not behavioural.
Architecture:
- New verifier/ npm workspace with package.json/tsconfig/server.ts.
Listens on 127.0.0.1:3001 by default. Tiny dep tree: express,
snarkjs, winston, uuid (no pg, no helmet — not customer-facing).
- POST /verify accepts proof + publicSignals (length 3) + optional
circuitVersion + correlationId. Returns verified bool + verifier
audit id + latency_ms + structuralFallback flag.
- GET /health reports loaded-vkey state + uptime; used by the API at
startup to fail loud if the verifier is misconfigured.
- The verifier trusts its caller — loopback-only is the trust
boundary. Never expose without mTLS + per-caller rate-limit (and
threat-model update + ADR).
API repo changes:
- src/services/zkp.ts shrinks: when VERIFIER_URL is set it becomes a
thin HTTP client; otherwise it falls back to the inline snarkjs path
(v0 behaviour, marked for removal after Friday Day 5's prod rollout).
- Replay defense (5-min timestamp window + UUIDv4 nonce check + signal
shape) stays in zkp.ts — the verifier is a pure crypto primitive.
- On-chain re-verification (when blockchain.verifyOnChain=true) stays
in zkp.ts — depends on ethers which the verifier doesn't need.
- isZKPReady() now reflects verifier /health (service mode) or inline
snarkjs load state (inline mode). getCircuitInfo() exposes the
active mode + URL for debugging.
Config:
- New env vars: VERIFIER_URL (default empty → inline mode),
VERIFIER_TIMEOUT_MS (default 2000). Per the plan-mode doc, these
ship today with production unchanged; tomorrow's PR adds the
verifier to docker-compose, sets VERIFIER_URL in prod .env, and
retires the inline fallback.
Tests:
- 68 → 73 passing. New tests/zkp-service-mode.test.ts has 5 cases:
POST shape correctness, verifier-says-pass, verifier-says-fail,
non-2xx returns false (no false positives on 500), network-error
returns false. Mocks global.fetch — no actual verifier needed for
CI.
- Existing tests stay green via the inline-fallback path (no
VERIFIER_URL in test env).
Verifier smoke (local):
npm run verifier:dev # boots on :3001
curl /health -> {"status":"ok","vkeyAvailable":true,...}
POST /verify with junk proof -> {"verified":false,"structuralFallback":false}
POST /verify with malformed body -> 400 invalid_request
Out of scope for today (Friday Day 5 PR):
- docker-compose dev/prod stack changes
- production .env VERIFIER_URL flip
- SQLite audit log + hash chain (B02 §4.3 design doc)
- Inline-fallback removal in src/services/zkp.ts
- Governance repo's docs/threat-model/verifier.md promotion from stub
- ADR-0008 capturing the TS-vs-Rust decision formally
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pulkitpareek18
added a commit
that referenced
this pull request
May 15, 2026
Plan B (TS workspace) chosen yesterday. Yesterday's PR #29 landed the verifier package in the repo. Today's PR Phase 2 flips production to actually use it instead of the inline-snarkjs fallback that's been serving since v0. Dockerfile: - Adds a `verifier-build` stage that npm-ci's the verifier workspace against the root lockfile (reproducible), compiles src/ → dist/. - Adds a `verifier-production` stage: slim alpine image, non-root user uid 1001, flat `npm install --omit=dev` (verifier has 4 prod deps: express, snarkjs, winston, uuid — workspace-aware ci complicates a per-package prod install; trade-off accepted per ADR-0005). Copies the compiled JS + the production vkey. Healthcheck on /health. Binds 0.0.0.0:3001 inside the container so docker network reaches it; no host port binding so it stays loopback-only at the boundary. docker-compose.yml: - New `zeroauth-verifier` service in BOTH the `dev` and `prod` profiles. `expose: 3001` (no `ports:` — no host binding). Healthcheck wired. - `zeroauth-prod` gains: VERIFIER_URL=http://zeroauth-verifier:3001 VERIFIER_TIMEOUT_MS=2000 in its `environment:` block (not via .env — wired directly so a hand-edited prod .env can't drift from the compose intent). - `zeroauth-prod.depends_on` now requires `zeroauth-verifier` to be service_healthy before starting. Deploy fails loud if the verifier can't load its vkey or bind its port. - `zeroauth-dev` gets the same wiring so local dev exercises the service path by default. Developers who want the inline-snarkjs fallback can override with `VERIFIER_URL=` in their .env. Local validation: - `docker build --target verifier-production` builds clean - `docker run` + `curl /health` returns {"status":"ok","version":"0.1.0","vkeyAvailable":true,"uptimeSeconds":5} - `POST /verify` with a structurally-valid junk proof exercises the real Groth16 verifier against the real vkey (structuralFallback:false) and rejects it correctly (verified:false, 543ms — first call cost includes snarkjs init; subsequent calls are <50ms in the same image). Post-deploy verification plan (after this PR merges): - The deploy workflow runs scripts/deploy-remote.sh which does `docker compose --profile prod up -d --build --remove-orphans` — that auto-picks-up the new zeroauth-verifier service. - After healthchecks pass, the API container's src/services/zkp.ts switches from the inline path to the HTTP path because VERIFIER_URL is now set in its environment. - I'll smoke-test by POSTing a /v1/auth/zkp/verify and confirming the API logs show "ZKP: verifier service: FAIL/PASS" with a verifierAuditId (the service path's signature in zkp.ts:212) instead of "ZKP: inline Groth16: …" (the legacy path's signature). Out of scope (separate follow-ups today): - SQLite append-only audit log + hash chain in the verifier (task 3) - ADR-0008 capturing the TS-vs-Rust decision formally (task 4) - Promotion of governance/docs/threat-model/verifier.md from stub → full with A-V01 through A-V05 entries (task 5) - Retirement of the inline-fallback code path in zkp.ts (next week) Tests: 228 passing (no change). Typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
pulkitpareek18
added a commit
that referenced
this pull request
May 15, 2026
* QA log — 2026-05-15 (HOLD, surrogate green, email NOW delivering) * B02 Phase 2: ship verifier as its own container in prod Plan B (TS workspace) chosen yesterday. Yesterday's PR #29 landed the verifier package in the repo. Today's PR Phase 2 flips production to actually use it instead of the inline-snarkjs fallback that's been serving since v0. Dockerfile: - Adds a `verifier-build` stage that npm-ci's the verifier workspace against the root lockfile (reproducible), compiles src/ → dist/. - Adds a `verifier-production` stage: slim alpine image, non-root user uid 1001, flat `npm install --omit=dev` (verifier has 4 prod deps: express, snarkjs, winston, uuid — workspace-aware ci complicates a per-package prod install; trade-off accepted per ADR-0005). Copies the compiled JS + the production vkey. Healthcheck on /health. Binds 0.0.0.0:3001 inside the container so docker network reaches it; no host port binding so it stays loopback-only at the boundary. docker-compose.yml: - New `zeroauth-verifier` service in BOTH the `dev` and `prod` profiles. `expose: 3001` (no `ports:` — no host binding). Healthcheck wired. - `zeroauth-prod` gains: VERIFIER_URL=http://zeroauth-verifier:3001 VERIFIER_TIMEOUT_MS=2000 in its `environment:` block (not via .env — wired directly so a hand-edited prod .env can't drift from the compose intent). - `zeroauth-prod.depends_on` now requires `zeroauth-verifier` to be service_healthy before starting. Deploy fails loud if the verifier can't load its vkey or bind its port. - `zeroauth-dev` gets the same wiring so local dev exercises the service path by default. Developers who want the inline-snarkjs fallback can override with `VERIFIER_URL=` in their .env. Local validation: - `docker build --target verifier-production` builds clean - `docker run` + `curl /health` returns {"status":"ok","version":"0.1.0","vkeyAvailable":true,"uptimeSeconds":5} - `POST /verify` with a structurally-valid junk proof exercises the real Groth16 verifier against the real vkey (structuralFallback:false) and rejects it correctly (verified:false, 543ms — first call cost includes snarkjs init; subsequent calls are <50ms in the same image). Post-deploy verification plan (after this PR merges): - The deploy workflow runs scripts/deploy-remote.sh which does `docker compose --profile prod up -d --build --remove-orphans` — that auto-picks-up the new zeroauth-verifier service. - After healthchecks pass, the API container's src/services/zkp.ts switches from the inline path to the HTTP path because VERIFIER_URL is now set in its environment. - I'll smoke-test by POSTing a /v1/auth/zkp/verify and confirming the API logs show "ZKP: verifier service: FAIL/PASS" with a verifierAuditId (the service path's signature in zkp.ts:212) instead of "ZKP: inline Groth16: …" (the legacy path's signature). Out of scope (separate follow-ups today): - SQLite append-only audit log + hash chain in the verifier (task 3) - ADR-0008 capturing the TS-vs-Rust decision formally (task 4) - Promotion of governance/docs/threat-model/verifier.md from stub → full with A-V01 through A-V05 entries (task 5) - Retirement of the inline-fallback code path in zkp.ts (next week) Tests: 228 passing (no change). Typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pulkitpareek18
added a commit
that referenced
this pull request
May 15, 2026
…29) * QA log — 2026-05-14 (Blocked + surrogate green, second DW01 run, first on-cadence) * B02 Plan B: split Groth16 verifier into @zeroauth/verifier workspace Per the plan-mode design doc, this is Plan B (TypeScript workspace, not Rust) — chosen for single-engineer velocity. The HTTP shape is Rust-compatible so a future swap is structural, not behavioural. Architecture: - New verifier/ npm workspace with package.json/tsconfig/server.ts. Listens on 127.0.0.1:3001 by default. Tiny dep tree: express, snarkjs, winston, uuid (no pg, no helmet — not customer-facing). - POST /verify accepts proof + publicSignals (length 3) + optional circuitVersion + correlationId. Returns verified bool + verifier audit id + latency_ms + structuralFallback flag. - GET /health reports loaded-vkey state + uptime; used by the API at startup to fail loud if the verifier is misconfigured. - The verifier trusts its caller — loopback-only is the trust boundary. Never expose without mTLS + per-caller rate-limit (and threat-model update + ADR). API repo changes: - src/services/zkp.ts shrinks: when VERIFIER_URL is set it becomes a thin HTTP client; otherwise it falls back to the inline snarkjs path (v0 behaviour, marked for removal after Friday Day 5's prod rollout). - Replay defense (5-min timestamp window + UUIDv4 nonce check + signal shape) stays in zkp.ts — the verifier is a pure crypto primitive. - On-chain re-verification (when blockchain.verifyOnChain=true) stays in zkp.ts — depends on ethers which the verifier doesn't need. - isZKPReady() now reflects verifier /health (service mode) or inline snarkjs load state (inline mode). getCircuitInfo() exposes the active mode + URL for debugging. Config: - New env vars: VERIFIER_URL (default empty → inline mode), VERIFIER_TIMEOUT_MS (default 2000). Per the plan-mode doc, these ship today with production unchanged; tomorrow's PR adds the verifier to docker-compose, sets VERIFIER_URL in prod .env, and retires the inline fallback. Tests: - 68 → 73 passing. New tests/zkp-service-mode.test.ts has 5 cases: POST shape correctness, verifier-says-pass, verifier-says-fail, non-2xx returns false (no false positives on 500), network-error returns false. Mocks global.fetch — no actual verifier needed for CI. - Existing tests stay green via the inline-fallback path (no VERIFIER_URL in test env). Verifier smoke (local): npm run verifier:dev # boots on :3001 curl /health -> {"status":"ok","vkeyAvailable":true,...} POST /verify with junk proof -> {"verified":false,"structuralFallback":false} POST /verify with malformed body -> 400 invalid_request Out of scope for today (Friday Day 5 PR): - docker-compose dev/prod stack changes - production .env VERIFIER_URL flip - SQLite audit log + hash chain (B02 §4.3 design doc) - Inline-fallback removal in src/services/zkp.ts - Governance repo's docs/threat-model/verifier.md promotion from stub - ADR-0008 capturing the TS-vs-Rust decision formally ---------
pulkitpareek18
added a commit
that referenced
this pull request
May 15, 2026
* QA log — 2026-05-15 (HOLD, surrogate green, email NOW delivering) * B02 Phase 2: ship verifier as its own container in prod Plan B (TS workspace) chosen yesterday. Yesterday's PR #29 landed the verifier package in the repo. Today's PR Phase 2 flips production to actually use it instead of the inline-snarkjs fallback that's been serving since v0. Dockerfile: - Adds a `verifier-build` stage that npm-ci's the verifier workspace against the root lockfile (reproducible), compiles src/ → dist/. - Adds a `verifier-production` stage: slim alpine image, non-root user uid 1001, flat `npm install --omit=dev` (verifier has 4 prod deps: express, snarkjs, winston, uuid — workspace-aware ci complicates a per-package prod install; trade-off accepted per ADR-0005). Copies the compiled JS + the production vkey. Healthcheck on /health. Binds 0.0.0.0:3001 inside the container so docker network reaches it; no host port binding so it stays loopback-only at the boundary. docker-compose.yml: - New `zeroauth-verifier` service in BOTH the `dev` and `prod` profiles. `expose: 3001` (no `ports:` — no host binding). Healthcheck wired. - `zeroauth-prod` gains: VERIFIER_URL=http://zeroauth-verifier:3001 VERIFIER_TIMEOUT_MS=2000 in its `environment:` block (not via .env — wired directly so a hand-edited prod .env can't drift from the compose intent). - `zeroauth-prod.depends_on` now requires `zeroauth-verifier` to be service_healthy before starting. Deploy fails loud if the verifier can't load its vkey or bind its port. - `zeroauth-dev` gets the same wiring so local dev exercises the service path by default. Developers who want the inline-snarkjs fallback can override with `VERIFIER_URL=` in their .env. Local validation: - `docker build --target verifier-production` builds clean - `docker run` + `curl /health` returns {"status":"ok","version":"0.1.0","vkeyAvailable":true,"uptimeSeconds":5} - `POST /verify` with a structurally-valid junk proof exercises the real Groth16 verifier against the real vkey (structuralFallback:false) and rejects it correctly (verified:false, 543ms — first call cost includes snarkjs init; subsequent calls are <50ms in the same image). Post-deploy verification plan (after this PR merges): - The deploy workflow runs scripts/deploy-remote.sh which does `docker compose --profile prod up -d --build --remove-orphans` — that auto-picks-up the new zeroauth-verifier service. - After healthchecks pass, the API container's src/services/zkp.ts switches from the inline path to the HTTP path because VERIFIER_URL is now set in its environment. - I'll smoke-test by POSTing a /v1/auth/zkp/verify and confirming the API logs show "ZKP: verifier service: FAIL/PASS" with a verifierAuditId (the service path's signature in zkp.ts:212) instead of "ZKP: inline Groth16: …" (the legacy path's signature). Out of scope (separate follow-ups today): - SQLite append-only audit log + hash chain in the verifier (task 3) - ADR-0008 capturing the TS-vs-Rust decision formally (task 4) - Promotion of governance/docs/threat-model/verifier.md from stub → full with A-V01 through A-V05 entries (task 5) - Retirement of the inline-fallback code path in zkp.ts (next week) Tests: 228 passing (no change). Typecheck clean. ---------
pulkitpareek18
pushed a commit
that referenced
this pull request
May 28, 2026
v0 storyboard for the bank pitch deck under docs/gtm/bank-pitch-deck-v0.md. Captures slide-by-slide speaker time, visual, speaker notes, pain-point trace, required engineering artefacts, compliance trace, and the failure-mode-if-cut for each of the 20 slides. The deck backs the 22-minute live demo and is the commercial spine of the Anchor Bank conversation. Every pain point referenced lifts directly from docs/plan/bfsi-v1/01-pain-points.md (P1 DPDP §8 reportable-breach, P2 Aadhaar e-KYC dependency, P3 SMS OTP cost + SIM-swap, P4 audit-log tamper evidence, P5 RBI Digital Lending consent, P6 ATO, P7 high-value transaction binding, P10 DPDP §2(t) + data-localisation). Demo handoffs on slides 8, 14, 15 reference scenes 1-5 of docs/plan/bfsi-v1/02-bank-demo.md and are operationally backed by docs/operations/anchor-bank-demo-runbook.md. Compliance slide 10 and roadmap slide 18 trace to docs/compliance/compliance-roadmap-v1.md quarterly milestones and deliverable IDs (D-Q1-05 DPDP §2(t) memo, D-Q2-06 ISO Stage 1, D-Q2-10 SOC 2 Type I report, D-Q3-06 RBI sandbox application, D-Q3-13 ISO 27001 certificate, D-Q4-02 SOC 2 Type II report, D-Q4-08 first paid bank). Ticket: A42-W2-Wed. Reviewers: Agents #28, #29, #48. Owner: Agent #42 (CRO). [no-test]
pulkitpareek18
pushed a commit
that referenced
this pull request
May 28, 2026
Agent #29 (Senior PM, BFSI) — week 1 tickets A29-W1-Mon through A29-W1-Fri. Delivers the six bank intel packs (HDFC, ICICI, Axis, SBI YONO, IDFC FIRST, RBL) plus the v1 cold-outreach sequence that Agent #43 (BFSI North) and Agent #44 (BFSI South + PSBs) consume for pre-call prep. Files added: - docs/product/bank-intel/README.md — index; explains that the packs are research-grade artefacts for pre-sales prep, not for external distribution; lists update cadence and language constraints. - docs/product/bank-intel/hdfc.md — HDFC Bank Ltd. intel pack; pain hooks P1, P4, P7 from docs/plan/bfsi-v1/01-pain-points.md. - docs/product/bank-intel/icici.md — ICICI Bank Ltd.; pain hooks P3, P6, P1. - docs/product/bank-intel/axis.md — Axis Bank Ltd.; pain hooks P4, P7, P1. - docs/product/bank-intel/sbi-yono.md — State Bank of India / YONO; pain hooks P2, P9, P6. - docs/product/bank-intel/idfc-first.md — IDFC FIRST Bank Ltd.; pain hooks P9, P3, P1. - docs/product/bank-intel/rbl.md — RBL Bank Ltd.; pain hooks P5, P4, P1. - docs/gtm/outreach-sequence-v1.md — five-email cold-outreach sequence (day 0, 4, 9, 16, 23); subject lines all <= 50 chars, bodies 100-150 words, per-bank personalisation map; no banned phrases from CLAUDE.md. Verification: - Each intel pack is 176-187 lines (target band 150-300). - Every fact is either cited [src: ...] or marked [VERIFY]. - No named executives without a verified public-record source. - Every file carries an INTERNAL header in the top three lines. - Banned-phrase scan clean: no "AI-powered", no "deepfake-immune" without the visual-spoofing-class qualifier, no "Dr. Pulkit", no "production stack". - Subject lines: all 22 variants fit <= 50 chars by Python len(). - Email bodies: word count 105-125 (target 100-150) excluding placeholder tokens. References: - docs/plan/bfsi-v1/01-pain-points.md (commercial spine; P1-P10). - docs/plan/bfsi-v1/02-bank-demo.md (demo Scenes 1-6 reflected in per-pack "why ZeroAuth resonates here" sections). - docs/plan/bfsi-v1/03-team.md role 29, 43, 44. - docs/operations/anchor-bank-demo-runbook.md (one-page summary PDF reference in Email 3). - docs/compliance/compliance-roadmap-v1.md (DPDP and RBI section references in the RBL pack and the SBI pack). [no-test] markdown-only.
pulkitpareek18
pushed a commit
that referenced
this pull request
May 28, 2026
v0 storyboard for the bank pitch deck under docs/gtm/bank-pitch-deck-v0.md. Captures slide-by-slide speaker time, visual, speaker notes, pain-point trace, required engineering artefacts, compliance trace, and the failure-mode-if-cut for each of the 20 slides. The deck backs the 22-minute live demo and is the commercial spine of the Anchor Bank conversation. Every pain point referenced lifts directly from docs/plan/bfsi-v1/01-pain-points.md (P1 DPDP §8 reportable-breach, P2 Aadhaar e-KYC dependency, P3 SMS OTP cost + SIM-swap, P4 audit-log tamper evidence, P5 RBI Digital Lending consent, P6 ATO, P7 high-value transaction binding, P10 DPDP §2(t) + data-localisation). Demo handoffs on slides 8, 14, 15 reference scenes 1-5 of docs/plan/bfsi-v1/02-bank-demo.md and are operationally backed by docs/operations/anchor-bank-demo-runbook.md. Compliance slide 10 and roadmap slide 18 trace to docs/compliance/compliance-roadmap-v1.md quarterly milestones and deliverable IDs (D-Q1-05 DPDP §2(t) memo, D-Q2-06 ISO Stage 1, D-Q2-10 SOC 2 Type I report, D-Q3-06 RBI sandbox application, D-Q3-13 ISO 27001 certificate, D-Q4-02 SOC 2 Type II report, D-Q4-08 first paid bank). Ticket: A42-W2-Wed. Reviewers: Agents #28, #29, #48. Owner: Agent #42 (CRO). [no-test]
pulkitpareek18
pushed a commit
that referenced
this pull request
May 28, 2026
Agent #29 (Senior PM, BFSI) — week 1 tickets A29-W1-Mon through A29-W1-Fri. Delivers the six bank intel packs (HDFC, ICICI, Axis, SBI YONO, IDFC FIRST, RBL) plus the v1 cold-outreach sequence that Agent #43 (BFSI North) and Agent #44 (BFSI South + PSBs) consume for pre-call prep. Files added: - docs/product/bank-intel/README.md — index; explains that the packs are research-grade artefacts for pre-sales prep, not for external distribution; lists update cadence and language constraints. - docs/product/bank-intel/hdfc.md — HDFC Bank Ltd. intel pack; pain hooks P1, P4, P7 from docs/plan/bfsi-v1/01-pain-points.md. - docs/product/bank-intel/icici.md — ICICI Bank Ltd.; pain hooks P3, P6, P1. - docs/product/bank-intel/axis.md — Axis Bank Ltd.; pain hooks P4, P7, P1. - docs/product/bank-intel/sbi-yono.md — State Bank of India / YONO; pain hooks P2, P9, P6. - docs/product/bank-intel/idfc-first.md — IDFC FIRST Bank Ltd.; pain hooks P9, P3, P1. - docs/product/bank-intel/rbl.md — RBL Bank Ltd.; pain hooks P5, P4, P1. - docs/gtm/outreach-sequence-v1.md — five-email cold-outreach sequence (day 0, 4, 9, 16, 23); subject lines all <= 50 chars, bodies 100-150 words, per-bank personalisation map; no banned phrases from CLAUDE.md. Verification: - Each intel pack is 176-187 lines (target band 150-300). - Every fact is either cited [src: ...] or marked [VERIFY]. - No named executives without a verified public-record source. - Every file carries an INTERNAL header in the top three lines. - Banned-phrase scan clean: no "AI-powered", no "deepfake-immune" without the visual-spoofing-class qualifier, no "Dr. Pulkit", no "production stack". - Subject lines: all 22 variants fit <= 50 chars by Python len(). - Email bodies: word count 105-125 (target 100-150) excluding placeholder tokens. References: - docs/plan/bfsi-v1/01-pain-points.md (commercial spine; P1-P10). - docs/plan/bfsi-v1/02-bank-demo.md (demo Scenes 1-6 reflected in per-pack "why ZeroAuth resonates here" sections). - docs/plan/bfsi-v1/03-team.md role 29, 43, 44. - docs/operations/anchor-bank-demo-runbook.md (one-page summary PDF reference in Email 3). - docs/compliance/compliance-roadmap-v1.md (DPDP and RBI section references in the RBL pack and the SBI pack). [no-test] markdown-only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Day 4 of Week 1. Today's demo battery cadence fired on time (09:55 IST, still HOLD); main work is the verifier service split.
Plan B chosen
Per yesterday's plan-mode design doc, TypeScript workspace instead of Rust separate repo. Picked for single-engineer velocity. HTTP shape is deliberately Rust-compatible — future swap is structural, not behavioural.
What ships
New `verifier/` workspace
API repo changes
Why production is safe to merge today
VERIFIER_URL is unset in production `/opt/zeroauth/.env`. That means after this PR lands and the deploy fires, prod `src/services/zkp.ts` runs the inline-fallback path — byte-identical behavior to before. The new verifier package ships in the bundle but doesn't run. Tomorrow's PR flips production over by (a) adding the verifier to docker-compose, (b) setting `VERIFIER_URL=http://verifier:3001\` in prod env, (c) retiring the inline fallback.
Test plan
Out of scope for this PR (Friday Day 5 work)
🤖 Generated with Claude Code