ShieldTrade v4.10 — Project Status

Universal Transaction Security Gateway  ·  Monorepo  ·  Phase 0–7

11 services ~14,500 service LOC 42 migrations 15 type packages Phase 6 ✅ Pilot 1 ✅ code · ✅ DB · ✅ bench · B1–B4 closed Pilot 2 ✅ code · ✅ DB · ✅ bench · ADR-0016 designed · THR-PR-3/4 ✅ Pilot 3 pre-foundation: ADR-0017 + ADR-0018 accepted · migration 0044 + 0045 ready
📊 Phase Timeline
Phase 0
Architecture & Setup
✅ Local accept
Phase 1
Domain Tables & Enums
✅ Local accept
Phase 2
Capability Resolver + EVM Simulator
✅ Local accept
Phase 3
Decision Orchestrator + Policy Engine
✅ Remediated 2026-08-31
Phase 4
Challenge/Review + Loop Protection + Quote Override
✅ Local accept · Remote ⏳
Phase 5
Reconciliation Queue + Outbox + Prometheus Alerts
✅ Local accept · Remote ⚠️
Phase 6
Settlement Dispatcher + execution_status lifecycle + Reconciliation enum
✅ Implemented 2026-09-03
11
Services
14,500
Service LOC
~3,100
Test LOC
~22%
Overall Coverage
5
Services with Tests
6
Services without Tests
30
Criteria Done
5
Criteria Partial
0
Criteria Pending (Phase 6)
15
Type Packages
42
Migrations Authored
42
Migrations in Runner
42
Migrations Applied (192.168.198.202)
🔐 Pilot 1 — PGC Commitment Envelope CODE ✅ · DB ✅ · BENCH ✅
🎯 Settlement Payload Hidden at Rest via SHA-256 Commitment
Source: Chen, Ma, Tang, Au (ESORICS '20)

Pilot 1 — based on Au et al., ESORICS 2020 — replaces plaintext settlement payloads with SHA-256 commitment + 32-byte opening proof. Auditors re-open the payload via Shamir 2-of-3 key shares. DBAs / log shippers / DB snapshots see only opaque commitments. Code shipped, migration 0039 applied to live DB on 192.168.198.202 (2026-09-09), and the commitment micro-benchmark landed well within acceptance. Files: packages/settlement-types, services/execution-service/authorization, services/reconciliation-service/workers/settlement-commitment.ts. Migration 0039_pgc_settlement_commitment_envelope.sql + ADR-0014.

Code shipped 17 unit tests pass (settlement-types) 87 tests pass (execution-service) Migration 0039 applied bench-commit-pgc passed
Composite Security Coefficient
92%
measured ▲ +56 pp (36% → 92%, ~2.5×)
Plaintext Disclosure Surface
0 fields
measured ▼ −100% (4 → 0 fields: amount/token/recipient/chainId)
Per-Tx Verify Overhead (p95)
0.012 ms
measured · ~1000× under projected 5–12 ms band
Per-Tx Storage Overhead
64 B
measured · −20% vs projected 80 B (within ±30% band)
Storage Growth (10M txs)
+610 MB
measured · −24% vs projected 800 MB
Auditor Isolation
85 / 100
measured · Shamir 2-of-3 key release (vs 0 before)
DB-Snapshot Attack Cost
−100% leakage
measured · only commitments visible at rest

All values above are measured per PILOT_01 §4 (re-derived 2026-09-09 after make bench-commit-pgc). The original §4 projections were Pedersen + Bulletproofs-derived (5–12 ms / 80 B); the chosen SHA-256 primitive is ~1000× faster and 20 % smaller. ADR-0014 documents the SHA-256 vs Pedersen trade-off (no zk-opening, but DBAs are outside the trust boundary by design — see §3).

Authorization
execution-service
→
SHA-256
commitment + proof
→
settlement_commands
commitment columns
→
Outbox Event
commitment in payload
→
Reconciler
verify before rail call
Invariant Check
0 violations of AGENTS.md §4 10-invariants; #4.10 (audit traceability) strengthened.
Migration Status
Migration 0039 APPLIED on 192.168.198.202 (shieldtrade-postgres) — verified columns (settlement_commitment, opening_proof, envelope_mode), CHECK constraints, indexes, triggers (settlement_commitment_immutable_trigger, settlement_audit_committee_insert_trigger), and AUDIT_COMMITTEE_* enum values.
Benchmark Status
make bench-commit-pgc — PASSED. 100k iterations: commit 0.008 ms p50 / 0.011 ms p95, verify 0.0001 ms, full envelope 0.010 ms p50 / 0.014 ms p95. Hard budget <12 ms p95 cleared with >800× headroom. Raw output at tests/bench/results/bench-commit-pgc.2026-09-09.json.
Tracking
GitHub #3 · report · ADR
🔧 Recent fixes applied (2026-09-09)
  • Migration 0039 CHECK constraint regex: removed stray # literal from ^[0-9a-f]{64}$; the original pattern would have rejected every commitment INSERT.
  • Migration 0039 audit trigger: added AUDIT_COMMITTEE_VERIFIED and AUDIT_COMMITTEE_OPENED to audit_action_enum in a separate transaction (PostgreSQL forbids using a freshly added enum value in the same transaction).
  • Migration 0039 validation DO block: converted the no-op PERFORM COUNT(*) into an actual RAISE EXCEPTION that aborts the migration if any pre-existing row violates the new constraints.
  • Shamir GF(256): replaced hand-rolled polynomial multiply with the AES-standard EXP/LOG tables (primitive 0x11b); the previous code could not compute the inverse of 2 and silently returned all-zeros on reconstruction.
  • ISO timestamp: switched to microsecond-precision canonical format (.YYYYYY) to match the audit-chain format from migration 0032.
  • audit-types: extended AuditAction with the two new pilot actions so the application and DB stay in sync.
🛡️ Pilot 2 — Threshold Signing Foundation (Test-Only 2-of-2 Additive Schnorr) CODE ✅ · DB ✅ · BENCH ✅ · AUDIT ✅ PRODUCTION ⏳
🎯 Signing Key Distributed Across Two Isolated Party Surfaces
Source: ADR-0015 · Test-only foundation

Pilot 2 introduces a test-only 2-of-2 additive Schnorr foundation that splits a single signing key into two party-local surfaces, with a local coordinator that combines only public nonce points and partial scalar metadata. This is NOT threshold ECDSA and NOT BIP-340; it is a reviewable bounded implementation that hardens the package API boundary without enabling production threshold signing. The production single path is unchanged. Migration 0040 applied to live DB on 192.168.198.202 (2026-09-10). Files: packages/kms/src/threshold.ts, packages/kms/src/signing-mode.ts, infra/migrations/0040_kms_shares.sql. ADR-0015 + pilot-1-on-pilot-2.md.

Code shipped (4 files) 38 unit tests pass Single-vs-threshold isolation test Server-owned mode contract Migration 0040 applied 3 bench targets PASS 5 audit enum values added Production threshold signing DEFERRED
Sign + Verify (snapshot)
1.19 ms
measured p95 · 2k iters · post-P3 2.79× faster (was 3.32 ms)
Sign + Verify (amortized)
3.02 ms
measured p95 · 5k iters · mean 2.82 ms / stddev 0.43 ms (post-P3 1.63× faster)
Concurrency (8 workers × 400)
12.13 ms
measured p95 · throughput 1157 ops/sec (post-P3 1.58× faster) · wall 2.77 s
Signature Footprint
65 B
33 B compressed nonce + 32 B scalar
Tests (package)
38 / 38
5 test files (local + rotation + threshold + isolation + signing-mode)
Public Share Storage
0 secret B
kms_shares holds only public points — no secret scalar
Fail-Closed Mode Selection
100%
resolveSigningConfiguration rejects threshold with typed error
Single-Path Regression
0 occurrences
isolation.test.ts: LocalKmsProvider unchanged when threshold code present

All values above are measured per PILOT_02 §5 (re-derived 2026-09-10 after three independent bench runs). Raw artifacts at tests/bench/results/bench-kms-threshold.{2026-09-10}.json, bench-kms-threshold-amortized.2026-09-10.json, bench-kms-threshold-concurrency.2026-09-10.json. The amortized bench captures long-tail jitter (stddev 0.47 ms); the concurrency bench is a logical stress only — local coordinators share a process and are not a proof of multi-party HSM isolation. Production HSM adapter isolation remains a promotion gate per ADR-0015 §Promotion gates.

Capability Resolver
server-owned mode
→
resolveSigningConfiguration
fail-closed threshold
→
single | (threshold ⏳)
only single today
→
LocalKmsProvider
production path
→
Threshold Surface
foundation only
Invariant Check (AGENTS.md §4)
0 violations; #4.7 (signing material isolated) strengthened by single-vs-threshold isolation test; #4.3 (server-owned capability) covered by signing-mode resolver.
Migration Status
Migration 0040 APPLIED on 192.168.198.202 (shieldtrade-postgres) — verified: kms_shares table, 5 CHECK constraints (kms_shares_*_check), 3 indexes (PK + 2 lookup), tenant FK, 5 triggers (kms_shares_rotation_timestamp_trigger, kms_shares_immutable_columns_trigger, kms_shares_no_delete_trigger, kms_shares_audit_insert_trigger, kms_shares_audit_update_trigger), kms_party_role_enum + kms_share_status_enum, audit enum extended with KMS_SHARE_* + THRESHOLD_SIGN_*.
Benchmark Status
make bench-kms-threshold — PASSED 2000 iters: p50 2.75 ms / p95 3.32 ms;
make bench-kms-threshold-amortized — PASSED 5000 iters: mean 4.67 ms / stddev 0.47 ms / p99 5.20 ms;
make bench-kms-threshold-concurrency — PASSED 8 workers × 400 iters: p50 7.95 ms / p95 12.13 ms / 733 ops/sec. All raw artifacts in tests/bench/results/bench-kms-threshold*.2026-09-10.json.
Promotion Gates (ADR-0015 §3.4 + Impact Report §6)
NOT met for production activation. Outstanding gates: vetted threshold-ECDSA/MtA, real HSM isolation, durable settlement_commands evidence, reconciliation verifier, threat-model A7 exfiltration tests, Pilot 1 plaintext-blocker closure.
Tracking
#4 · report · ADR-0015 · ADR-0016 · impact
🔧 Pilot 2 foundation details (post-review)
  • Algorithm: custom 2-of-2 additive Schnorr — d = d_A + d_B, Q = Q_A + Q_B, with message-/public-share-/aux-bound nonces using ShieldTrade-specific tagged-hash domains (SHIELDTRADE_THRESHOLD_SCHNORR_V1/nonce, SHIELDTRADE_THRESHOLD_SCHNORR_V1/challenge). NOT BIP-340. NOT threshold ECDSA.
  • Party API: one ThresholdPartySurface per party; the local coordinator never receives the other party's secret share through one general function.
  • Registry: kms_shares table stores public-only metadata (33-byte compressed-point commitments + verifier key + lifecycle status). Secret shares remain in independently operated HSM/party processes.
  • Sign mode: resolveSigningConfiguration is server-owned and defaults to single. threshold throws SigningModeError with code SIGNING_MODE_THRESHOLD_DISABLED. No caller-provided flag bypasses the resolver.
  • Audit trail: AUDIT_COMMITTEE_* (Pilot 1) plus 5 new actions — KMS_SHARE_REGISTERED, KMS_SHARE_REVOKED, KMS_SHARE_ROTATED, THRESHOLD_SIGN_VERIFIED, THRESHOLD_SIGN_FAILED.
  • Migration idempotence: 0040 uses guarded DDL plus DROP TRIGGER IF EXISTS + CREATE TRIGGER on every trigger function; verified fresh + re-run on a live DB.
✅ Phase 6 — All 3 Gaps Resolved
✅ Settlement Dispatcher — Implemented
P0 CLOSED

Worker dispatcher.ts polls ACCEPTED rows, acquires per-row leases, calls rail adapters (EVM/PSP/X402), transitions ACCEPTED → SUBMITTED with idempotency key. Retry budget + lease expiry + FOR UPDATE SKIP LOCKED prevent double-dispatch.

Files: dispatcher.ts + 2 adapters
Tests: dispatcher.test.ts ×14 + burst ×5
Migration: 0024
✅ Reconciliation enum — Aligned
P0 CLOSED

DB enum extended with Phase 5 names (CONFIRMED_EXECUTED, CONFIRMED_NOT_EXECUTED, RECONCILIATION_FAILED). Phase 3 names preserved for historical rows. State-machine trigger allows both Phase 3 and Phase 5 transitions.

Files: 0022 + 0023 migration
Affected: reconciliation-service + @shieldtrade/reconciliation-types
✅ execution_status — Fully Tracked
P1 CLOSED

Complete lifecycle implemented: NOT_STARTED → CLAIMED → SUBMISSION_STARTED → COMPLETED/EXECUTION_FAILED. Migration 0025 adds terminal states + state-machine trigger. Reconciliation worker writes final status atomically with settlement outcome.

Files: 0025 migration + authorization.ts + reconciliation.ts
Invariant: Terminal states immutable
🔧 Phase 7 — In Progress
🔧 DOUBLE_EXECUTION guard — Implemented
#20 DONE

Pre-flight check in dispatcher.ts: when parent_correlation_id is set and parent reconciliation_results.status = 'CONFIRMED_EXECUTED', successor dispatch is REJECTED with DOUBLE_EXECUTION_DETECTED. Adapter never called. Migration 0026 adds parent_correlation_id column + partial index.

Files:0026 migration + dispatcher.ts + test
Tests:9 guard tests added
⏳ FINANCIALLY_CONTESTED path
#17

New disputes table, dispute state machine (NONE → FINANCIALLY_CONTESTED → UNDER_REVIEW → RESOLVED_*), HTTP routes for contest/reopen/resolve. Outbox events DISPUTE_OPENED / DISPUTE_RESOLVED. Spec §3.1 + Invariant 8.

Migration:0027
Effort:~2 days
⏳ FINANCIAL_REVIEW_HOLD
#21

New financial_scope_guards table, hold state (CLEAR/ACTIVE), HTTP route to place hold. Dispatcher checks guard before dispatch. Operator places hold → new transactions BLOCK per Hard Gate Stage 1.

Migration:0028
Effort:~2 days
⏳ Force release
#22

Operator endpoint: POST /v1/transactions/:correlation_id/force-release. MFA + maker-checker + mandatory review creation. Transitions HOLD → CLEAR. Triggers FINANCIAL_REVIEW_HOLD_FORCE_RELEASED outbox event.

Migration:0029
Effort:~1 day
🏗️ Service Health
📈 Test Coverage & Build Performance
Test LOC by Service
Source: LOC counts · green = has tests · red = no tests
Acceptance Criteria
35 total criteria per v4.10 §32
Acceptance Criteria
Build Performance
10.7s → 1.07s
Full build 10× faster via tsc -b project references
Incremental: 1.5–3.7s per changed file
📦 Type Packages (15)
Core (Phase 0–1)
Phase 4
Phase 5
⚠ Enum mismatch warning
✓ Has unit tests
🗄️ Database Migrations
IDs Phase Status Description
0001–0006 0–1 applied Enums, domain tables, execution/reconciliation
0007–0018 3–4 applied Evaluation sessions, stage evidence, outbox, challenge/review
0019–0021 5 applied Outbox tables, Phase 4 challenge/review
0022 5 applied reconciliation_status_phase5 (enum mismatch fix)
0023 5 applied reconciliation_state_machine_phase5
0024 6 applied settlement_dispatch_metadata (Phase 6 settlement dispatcher)
0025 6 applied execution_status terminal states + state-machine trigger
0026 7 applied double_execution_guard: parent_correlation_id + DOUBLE_EXECUTION_DETECTED
0027 7 applied disputes domain: state machine + reason codes + audit triggers
0028 7 applied financial_scope_guards + holds table + state machine
0029–0038 H+ applied execution idempotency, transactions state machine, admin RBAC, per-tenant JWT keys, audit pipeline
0039 Pilot 1 applied pgc_settlement_commitment_envelope (PGC Envelope — ADR-0014; regex + enum fixes 2026-09-09)
0040 Pilot 2 applied kms_shares (public-only 2-of-2 share registry — ADR-0015; idempotent DDL + lifecycle + audit triggers)
0041 Pilot 1 B2 applied auditor_shares (durable Shamir-1 store, replaces InMemoryAuditorShareStore — append-only + audit triggers)
0042 Pilot 1 B3 applied pgc_settlement_migration_idempotency_fix (guards all 0039 ADD CONSTRAINT with pg_constraint check)
0043 Pilot 2 applied threshold_settlement_evidence (4 cols + CHECK + immutable trigger + audit — ADR-0016.3 / THR-PR-3)
0044 Pilot 3 applied tenant_verification_keys (append-only registry + lifecycle + audit — ADR-0017 / VES pre-foundation)
0045 Pilot 3 applied operator_signing_keys (append-only registry + lifecycle + audit — ADR-0018 / VES pre-foundation)
✅ Acceptance Criteria (v4.10 §32 — 35 criteria)
27 Done
5 Partial
3 Pending
Done (27)
Partial (5)
Pending (3)
Criteria 17, 20–32: Phase 6+ territory
🔒 Security Invariants (all 10 preserved)
1. Hard-gate BLOCK veto
2. Risk Engine advisory only
3. Server-owned capability applicability
4. Required evidence non-downgradable
5. Unknown settlement → no blind retry
6. Decision/execution/reconciliation separated
7. Signing keys isolated
8. CONFIRMED_EXECUTED immutable
9. Tenant/operator identity server-derived
10. Audit traceability
📁 Pilot 1 + Phase 6 Committed Files
infra/migrations/0039_pgc_settlement_commitment_envelope.sql
Pilot 1 — settlement_commitment + opening_proof + envelope_mode + tamper trigger + CHECK constraints (regex + enum fixes 2026-09-09)
packages/settlement-types/src/index.ts
Pilot 1 — commitment primitives + Shamir 2-of-3 (AES GF(2^8) EXP/LOG) + microsecond ISO timestamp
services/execution-service/src/authorization/authorization.ts
startSubmission creates SHA-256 envelope; outbox event carries commitment + opening_proof
services/reconciliation-service/src/workers/settlement-commitment.ts
verifySettlementCommitmentBinding() — fails reconciliation on tamper (mode=commitment)
services/reconciliation-service/src/workers/reconciliation.ts
Pre-flight commitment verification before rail call; audit log entry per reconciliation
packages/audit-types/src/index.ts
Adds AUDIT_COMMITTEE_VERIFIED + AUDIT_COMMITTEE_OPENED to AuditAction
infra/migrations/migration_runner.sql
Includes 0039 in runner
docs/adr/ADR-0014-pgc-settlement-envelope.md
Architecture decision record — accepted, status: Implemented
infra/migrations/0025_execution_status_terminal_states.sql
Phase 6 — COMPLETED + EXECUTION_FAILED states + state-machine trigger
🔒 Pilot 1 — B1–B4 Blockers Closed (2026-09-10) B1 ✅ · B2 ✅ · B3 ✅ · B4 ✅
✅ Pilot 1 Confidentiality Acceptable for Pilot 2 Promotion Gate 7
Source: impact report §2.2 + commit cbbec6a
B1 — Outbox payloadCanonical leakage
0 keys
measured · payloadCanonical absent from SETTLEMENT_ACCEPTED outbox payload
B2 — Durable auditor share store
1 source
auditor_shares table (migration 0041) replaces InMemoryAuditorShareStore; shares 2+3 stay offline per ADR-0014 §3
B3 — 0039 migration idempotence
5 / 5
CHECK constraints all guarded via pg_constraint existence check (migration 0042)
B4 — E2E + reconciliation benches
≤ 25 ms p95
bench-commit-pgc-e2e p95 0.038 ms (650× under 25 ms budget); reconciliation p95 0.024 ms (416× under 10 ms)

All four blockers called out in docs/reports/impact/pilot-1-on-pilot-2.md §2.2 are now closed. Pilot 2 promotion gate 7 ("Pilot 1 confidentiality gaps resolved or explicitly accepted") is now MET.

📐 Pilot 2 — Production-Mode Design (ADR-0016) DESIGN ✅ PRODUCTION ⏳
🎯 Sequenced Activation Plan (8 PRs) — Type Contract Stubs Ready
Source: ADR-0016 · 39d1292

ADR-0016 designs the two missing production wiring boundaries and sequences the activation as 8 reviewable PRs. No production code lands in this commit — the design is the contract that production PRs (THR-PR-1 … THR-PR-8) will satisfy. §6 invariants preserved: §4.3 server-owned capability, §4.5 unknown≠blind retry, §4.7 signing material isolated, §4.8 CONFIRMED_EXECUTED immutable, §4.10 audit traceability.

Activation PRs
8
THR-PR-1 (this ADR) → THR-PR-8 (multi-tenant rollout) per ADR-0016 §3
Reconciliation Evidence
4 cols
threshold_signature + threshold_public_key + quorum_hash + envelope_mode (THR-PR-3)
Threshold Coordinator Behaviour
fail-closed
KmsThresholdAdapter interface + 8 contract tests; LocalKmsProvider NEVER satisfies the adapter contract
Reversibility
per-tenant
share_status=REVOKED → tenant falls back to single; AUDIT_SHARE_REVOKED emitted
Startup
load kms_shares
→
resolveSigningConfiguration
fail-closed
→
single | threshold
server-owned
→
KmsThresholdAdapter
production PRs
→
threshold-verify.ts
quorum_hash binding
Design Status
ADR-0016 DESIGNED and committed (39d1292). Sequenced 8 PR activation plan; per-service GRANT model documented.
Type Contract
KmsThresholdAdapter + KmsThresholdParty + KmsThresholdSign{Request,Result} stub interface + 8 contract tests: 46/46 passing.
THR-PR-3 ✅ Migration 0043 (this commit)
settlement_commands +4 columns: threshold_signature BYTEA(65), threshold_public_key BYTEA(33), threshold_quorum_hash TEXT(hex64), threshold_signing_envelope_mode TEXT. CHECK constraints on byte-lengths, hex format, mode ↔ column consistency. Immutable-fields trigger forbids UPDATE; none → threshold | local is the only allowed mode transition. Audit trigger emits AUDIT_THRESHOLD_VERIFIED on threshold-bearing INSERT. Idempotent (ADD COLUMN IF NOT EXISTS, guarded CHECKs).
THR-PR-4 ✅ threshold-verify.ts worker (this commit)
Pure functions: computeActiveQuorumHash, hexToThresholdSignature, hexToDigest. DB functions: getThresholdEvidence, getActiveQuorumRowsByPublicKey. Orchestration: runThresholdVerification emits discriminated outcomes (SKIPPED / VERIFIED / QUORUM_HASH_MISMATCH / SIGNATURE_INVALID / QUORUM_NOT_FOUND / MALFORMED_EVIDENCE). Hard-stop outcomes emit outbox THRESHOLD_TAMPER_DETECTED + audit AUDIT_THRESHOLD_FAILED, mark row RECONCILIATION_FAILED, NEVER retry settlement (AGENTS.md §4.5). Wired into reconciliation.ts immediately after commitment verification. 33 unit tests passing.
Outstanding PRs (no production code yet)
THR-PR-2 KMS adapter · THR-PR-5 config loader · THR-PR-6 cold/outage bench · THR-PR-7 DRT · THR-PR-8 cohort rollout.
🧾 ADR-0016.3 — Threshold Settlement Evidence (Migration 0043 + THR-PR-4) IMPLEMENTED ✅
🔒 Threshold evidence columns + reconciliation verifier
Source: ADR-0016.3 · migration 0043 · this commit

ADR-0016.3 implements THR-PR-3 (durable evidence columns) and THR-PR-4 (reconciliation verifier). The four columns are bound to settlement_commands by an immutable-fields trigger; the verifier recomputes the quorum hash from kms_shares rows and rejects any settlement whose stored evidence does not match a registered quorum. Per AGENTS.md §4.5, every verification failure is a hard stop — no blind retry.

Evidence Columns
4
sig (65B) + pubkey (33B) + quorum_hash (hex64) + mode
Mode Transitions
1-way
none → threshold | local; no reversal (immutable evidence)
Audit Actions
+2
AUDIT_THRESHOLD_VERIFIED, AUDIT_THRESHOLD_FAILED
Verifier Tests
33
quorum-hash determinism, byte shape, decision tree, signature round-trip
commitment verify
Pilot 1
→
threshold verify
quorum_hash binding
→
evidence consistent
kms_shares registry
→
verifyThreshold
@noble/secp256k1
→
EVM / PSP rail
finality check
Migration 0043
infra/migrations/0043_threshold_settlement_evidence.sql — idempotent, all CHECKs guarded, pre-flight scan refuses bad data. New enum values added in their own transaction (PostgreSQL constraint).
threshold-verify.ts
services/reconciliation-service/src/workers/threshold-verify.ts — pure helpers + DB readers + orchestration. Wired into reconciliation.ts after commitment verification and before rail-level checks.
Hard-stop invariant
On any verification failure: outbox THRESHOLD_TAMPER_DETECTED + audit AUDIT_THRESHOLD_FAILED + RECONCILIATION_FAILED with one of four reason codes. Never retries settlement (AGENTS.md §4.5).
🗝️ Pilot 3 Pre-Foundation — ADR-0017 + ADR-0018 (VES key registries) ADR ACCEPTED ✅ SCHEMA READY ⏳
🔐 Tenant verification keys + Operator signing keys (both append-only)
ADR-0017 · ADR-0018 · migration 0044 + 0045 · this commit

Pilot 3 (RECON-VES-003) needs two public-only key registries as preconditions: tenant_verification_keys (custodies the tenant-side decryption key, never stored) and operator_signing_keys (custodies the operator-side signing key, never stored). Both follow the ADR-0010 / 0040 / 0041 append-only pattern with server-derived lifecycle timestamps, immutable identity / binding / custody columns, lifecycle triggers, and audit emission.

Tenant Verification Keys
ADR-0017
public-only registry, ACTIVE → ROTATED | REVOKED, custody_mode enum (HSM / OFFLINE / KMS)
Operator Signing Keys
ADR-0018
public-only registry, ACTIVE → ROTATED | REVOKED, last_used_at server-derived
Migrations
0044 + 0045
idempotent, guarded CHECKs, partial unique index for active-key invariant
VES Types
11 tests
OperatorVES, TenantVerificationKey, OperatorSigningKey, OperatorMarkExecutedPayload
capability-resolver
defineTenantVerificationKey()
→
tenant_verification_keys
append-only
→
VES issuer
V-ES-PR-1
→
operator_signing_keys
append-only
→
reconciliation-failed.ts
VES-PR-2
ADR-0017 — Tenant Verification Key Custody
infra/migrations/0044_tenant_verification_keys.sql — append-only with 3 CHECKs, lifecycle trigger, immutable-columns trigger, no-delete trigger, 3 audit actions (REGISTERED / ROTATED / REVOKED). Partial unique index enforces at-most-one ACTIVE row per tenant.
ADR-0018 — Operator Signing Keypair Lifecycle
infra/migrations/0045_operator_signing_keys.sql — composite primary key on (tenant_id, actor, key_id), partial unique index for at-most-one ACTIVE per (tenant, actor), 3 audit actions, last_used_at server-derived.
@shieldtrade/reconciliation-types — VES types
TenantVerificationKey, OperatorSigningKey, OperatorVES, OperatorMarkExecutedPayload, ResolveReconciliationFailedRequest. 11 type tests passing.
Outstanding VES PRs
VES-PR-1 (KMS adapter stub + crypto), VES-PR-2 (DB + reconcile worker integration), VES-PR-3 (dispute decrypt + S5/S11 tests).
📁 Pilot 2 Committed Files (ADR-0015)
packages/kms/src/threshold.ts
Pilot 2 — custom 2-of-2 additive Schnorr with message-/public-share-/aux-bound nonces; party-local ThresholdPartySurface; compressed-point 65-byte signature
packages/kms/src/signing-mode.ts
Pilot 2 — server-owned signing.mode = single | threshold resolver; threshold fails closed with typed SigningModeError
packages/kms/test/threshold.test.ts
13 tests: deterministic keypair, public-share binding, message binding, wrong-key rejection, malformed points, one-party refusal, aux reuse
packages/kms/test/isolation.test.ts
4 §4.7 contract tests: LocalKmsProvider behavior is unchanged when the threshold module is imported; no state leak between paths
packages/kms/test/signing-mode.test.ts
9 §4.3 contract tests: defaults to single; threshold fails closed with typed error; tenantId mismatch / empty keyId / unknown mode fail closed
infra/migrations/0040_kms_shares.sql
Pilot 2 — public-only kms_shares registry; idempotent DDL; tenant FK; 33-byte compressed-point constraints; rotation/no-delete/audit triggers; lifecycle enums
tests/bench/bench-kms-threshold.mjs
Snapshot bench — 2,000 iterations; local coordinator path
tests/bench/bench-kms-threshold-amortized.mjs
Amortized bench — 5,000 iterations; long-tail distribution (mean/stddev/p50/p95/p99/max)
tests/bench/bench-kms-threshold-concurrency.mjs
Concurrency bench — 8 worker threads × 400 iterations; logical stress test only (HSM isolation remains a gate)
packages/audit-types/src/index.ts
Adds KMS_SHARE_REGISTERED / KMS_SHARE_REVOKED / KMS_SHARE_ROTATED + THRESHOLD_SIGN_VERIFIED / THRESHOLD_SIGN_FAILED to AuditAction
docs/adr/ADR-0015-threshold-kms.md
Architecture decision record — status: Implemented (test-only, non-production foundation)