# Neural-Trader Performance Notes — ADR-126 follow-up #49

Bench-driven hot-path analysis derived from the three baseline benches
landed in `#48`:

- `benchmarks/signal-generation.bench.mjs`
- `benchmarks/backtest-throughput.bench.mjs`
- `benchmarks/memory-recall.bench.mjs`

The portfolio CG bench (`portfolio-cg.bench.mjs`) is owned by the
ADR-126 Phase 3 / #2080 work and is referenced read-only here.

## Hotspots ranked by user-visible impact

### 1. Neumann solver per-iter allocation (FIXED in this PR)

- **Where**: `plugins/ruflo-neural-trader/src/sublinear-adapter.mjs:148-184`
  (`neumannSeries` exported kernel)
- **Measured before**: avg ~0.635 ms at n=256 across 5 runs, plus measurable
  GC variance (p95 / max well above p50)
- **Measured after**: avg ~0.522 ms at n=256 across 5 runs — **~18% faster**
- **Optimization**: replace per-iter `new Float64Array(n)` allocation with
  a two-buffer ping-pong (`cur` / `next`, swapped by reference each iter).
  At n=256 a typical 5-iter solve previously allocated 5×2 KB of garbage
  per call — eliminated.
- **Scope**: plugin-layer only. No upstream `neural-trader` change needed.
  Smoke `node scripts/smoke-neural-trader-portfolio-cg.mjs` still passes.
- **Parity preserved**: `||cg − neumann||_∞ = 2.12e-8` at n=256 — identical
  to the pre-change baseline; the change is purely an allocation-pattern
  rewrite, not an algorithmic change.

### 2. Memory recall linear scan grows ~O(N) (TRACKED, not fixed here)

- **Where**: the production path uses `mcp__claude-flow__memory_search`
  via AgentDB + HNSW. The bench `memory-recall.bench.mjs` models the
  linear-scan baseline (cosine over Float32Array) to track the
  approximate-vs-exact recall gap an ANN index would create.
- **Measured**: avg latency scales from 0.08 ms at N=100 → 3.85 ms at
  N=5000 → 47.87× scaling vs the ideal-linear 50× (so 96% of linear).
  p95 at N=5000 is ~4.2 ms.
- **Proposed optimization (UPSTREAM)**: the production `memory_search`
  already uses HNSW per ADR-006, which gives 150x–12,500× speedups on
  this exact workload. The plugin doesn't need a local change — what we
  DO need is a regression gate: when the skill's recall@10 drops below
  0.8, the HNSW build params (M, efConstruction) drifted and need a
  rebuild. The bench captures that gate. **Scope: upstream HNSW config,
  not the plugin.**

### 3. Signal-scan p99 tail latency is ~9× the avg (TRACKED, not fixed here)

- **Where**: `benchmarks/signal-generation.bench.mjs` — for AAPL the
  measured avg is 22 µs but p99 is 191 µs.
- **Hypothesis**: GC pressure from `bars.map(b => b.close)` + two
  `bars.slice` calls per scan in the bench. The production `--signal scan`
  path is upstream (`npx neural-trader`) and we can't fix it in the
  plugin layer, but the bench is illustrative.
- **Proposed optimization (UPSTREAM)**: reuse a single typed array for
  `closes` and slice via indices instead of materializing sub-arrays.
  Saves ~3 allocations per scan call.
- **Scope**: upstream `neural-trader` binary if the same pattern exists
  in the Rust/NAPI code path — confirmed only by profiling the
  `--signal scan` cloud roundtrip, which the plugin can't reach from a
  pure-JS smoke.

## Out-of-scope / explicitly NOT optimized

- **`canonicalBytes` (signed-artifact.mjs:75 / signed-attribution.mjs:193)** —
  the explicit ADR-126 Phase 4 contract is `JSON.stringify` with NO key
  sort, deterministic-by-construction. Adding a sort or memoization
  would break the smoke's CWE-347 parity with the plugin-registry
  signer. Leave as-is.
- **`isSymmetric` (sublinear-adapter.mjs:204-211)** — already short-circuits
  on first violation. The full upper-triangle scan on symmetric inputs
  is the contract guard the smoke depends on; weakening it weakens the
  SPD precondition.

## Bench-as-regression-gate

The three new benches act as a perf budget:

| Bench                          | Budget                | Source              |
|--------------------------------|-----------------------|---------------------|
| signal worst-symbol avg        | <1000 µs              | acceptance line     |
| signal full-scan sum-of-avgs   | <10 ms                | acceptance line     |
| backtest avg runtime           | <10 ms                | acceptance line     |
| backtest throughput            | >25,000 bars/sec      | acceptance line     |
| memory-recall p95 at N=5000    | <50 ms                | acceptance line     |
| memory-recall recall@10        | >=0.8 (90% subset)    | acceptance line     |

A bench whose acceptance line trips on CI is a perf regression.

## Refs

- ADR-126 §SOTA delta — bench-driven perf work
- ADR-123 Wedge 8 — sublinear-time-solver
- ADR-006 — Unified Memory Service (HNSW)
- Followup #48 — bench suite that produced the numbers above
