Skip to content

Repository files navigation

Needle 2: Pure-JavaScript Engine with Native Parity for Vintage ARMv7 Android

A full implementation and runtime execution of the Needle 2 transformer model (27 layers, 4-lane mHC routing, Engram Rings, CQ2/CQ4 hybrid quantization, and an Attention Pooling Confidence Head) written in pure JavaScript (ES5/ES6)[cite: 7]. The engine runs directly inside the web browser of a vintage 2016 Android 5.1.1 (Lollipop) device with only 1 GB RAM, achieving functional and operational parity with the official native C / Python reference implementation[cite: 3, 4, 7].


1. Hardware & Software Stack

Target Device (Edge Inference)

  • Device: Lenovo Vibe C (A2020a40 / a1z)[cite: 7]
  • SoC: Qualcomm Snapdragon 210 (MSM8909)[cite: 7]
  • CPU: Quad-core ARM Cortex-A7 @ 1.1 GHz (32-bit ARMv7-A)[cite: 7]
  • RAM: 1 GB LPDDR3 (~250–350 MB available application headroom)[cite: 7]
  • OS: Android 5.1.1 (Lollipop, API Level 22)[cite: 7]
  • Execution Environment: Firefox for Android (Gecko Engine) / Android System WebView[cite: 7]

Host & Development Environment

  • Host Machine: x86_64 Linux (Lubuntu)[cite: 7]
  • Server: Standalone Node.js LAN server (zero external dependencies)[cite: 7]
  • Reference Oracle: QPython 3 / Native C ARMv7 ELF binary (needle-native-complete-oracle, A31)[cite: 3, 7]
  • Toolchain: Node.js, Android Debug Bridge (adb), sed/awk[cite: 7]

2. Architecture & Technical Challenges

The Needle 2 architecture was specifically engineered for extremely resource-constrained edge devices[cite: 7]:

  • 27 Transformer Layers with hybrid quantization (CQ2 on linear projection layers, CQ4 on feed-forward blocks)[cite: 7].
  • Multi-Head Routing (mHC 4-lane): Per-layer information stream branching, gating, and merging[cite: 7].
  • Engram Rings: Local n-gram associative memory mechanism using circular accumulator buffers (taps 0..3)[cite: 7].
  • Attention Pooling Confidence Head: Real-time confidence scoring module evaluating the necessity of structured tool calls[cite: 1, 2, 4, 7].

Core Challenges in Pure-JavaScript

  1. FP32 Drift & Reasoning Loops: Accumulation of subtle floating-point differences between hardware ARM NEON assembly and JS engines (SpiderMonkey/V8) became pronounced by Layer 13, causing greedy decoding to get trapped in repetitive reasoning loops[cite: 7].
  2. Out of Memory (OOM / SIGSEGV exit -11): Strict Low-Memory Killer (LMK) heuristics on Android 5.1 immediately terminated any browser tab exceeding the low memory ceiling[cite: 7].
  3. Structured Grammar Constraints: Enforcing strict, deterministic JSON generation for function arguments without relying on bulky native parsing engines or GBNF libraries[cite: 7].

3. Implemented Solutions (Engine & Web Patches)

A. Engine Patches (engine-full.js - A55 Suite)

  1. Engram Rolling Hash Parity (nativeEngramHash):
    • Harmonized the n-gram rolling hash implementation to match the native C arithmetic bit-for-bit[cite: 7].
  2. NEON CQ2 Sub4 Vector Kernel (nativeIntDotCQ2Neon):
    • Replaced the naive scalar CQ2 kernel with an exact software emulation of the native packed NEON assembly dot product (s01 / s23 signed accumulations), eliminating floating-point divergence[cite: 7].
  3. CQ2 Dispatch Routing:
    • Explicitly directed the following projection layers through the bit-exact NEON CQ2 kernel[cite: 7]:
      • engram.[01].(key_proj|value_proj)[cite: 7]
      • layer.6.out_proj[cite: 7]
      • layer.8.out_proj[cite: 7]
      • layer.11.out_proj[cite: 7]
  4. Engram Ring Native Cache (EngramRing):
    • Migrated memory caching to int8 + scale (32-wide quantization blocks) and resolved tap0 pipeline ordering: RAWV vectors are quantized and cached prior to evaluating taps 0..3[cite: 7].

B. Web Client & Output Normalization (index.html)

  1. Attention Pooling Head Integration:
    • Introduced engine.confidenceReset() prior to prompt framing prefill[cite: 7].
    • Polled engine.confidenceValue() during envelope finalization to populate the confidence metric[cite: 1, 2, 4, 7].
  2. Tokenizer Output Normalization (normalizeGeneratedPieces):
    • Decoded SentencePiece whitespace markers (\u2581) into standard spaces[cite: 2, 4, 7].
    • Stripped byte-level newline delimiters <0x0A> and applied a safe .trim()[cite: 2, 4, 7].
    • Ensured "reason": null is cleanly assigned whenever no text generation precedes the tool call[cite: 2, 4, 7].

4. Architectural Non-Goals & Rejected Approaches

  • Rejection of WebAssembly / WASM SIMD:
    • Rationale: Legacy mobile browsers on Android 5.1.1 (32-bit Cortex-A7) either lack WASM SIMD instructions entirely or suffer from instability and SIGSEGV crashes under heavy heap pressure[cite: 7]. Pure ES5/ES6 JavaScript using Typed Arrays (Float32Array, Int8Array) guarantees universal execution[cite: 7].
  • Rejection of Diagnostic Tracing Hooks in Production:
    • Rationale: Trace hooks (lanes=newLanes; if(this._a44Trace)...) used during diagnostic isolation caused significant garbage collection churn and latency[cite: 7]. These were stripped from the production runtime[cite: 7].
  • Rejection of Hardcoded Reasoning / Branch Forcing:
    • Rationale: The execution runtime does not artificially force tool call transitions[cite: 7]. The model autonomously decides between <think>, <tool_call>, or regular conversational tokens based on native logits[cite: 7].
  • Rejection of Arbitrary Confidence Calibration:
    • Rationale: Rather than applying arbitrary linear scalers to artificially match native scores, the raw floating-point score is surfaced transparently (confidence_calibrated_to_native: false)[cite: 1, 2, 4, 7].

5. Comparative Evaluation: Pure-JS vs Native ARMv7 Oracle

Parameter Native C / Python Oracle (QPython3 A31) Pure-JS Engine (Firefox A2020a40) Parity Status
Tool Execution set_light({"on": true})[cite: 3, 7] set_light({"on": true})[cite: 1, 2, 4, 7] Bit-exact Match[cite: 7]
Direct Command ("Turn the lights on.") Skip reasoning (reasoning: null)[cite: 3, 7] Skip reasoning (reasoning: null)[cite: 1, 7] Identical Flow[cite: 7]
Ambiguous Command ("It's too dark to see.") Enters <think> state[cite: 3, 7] Enters <think> state[cite: 2, 4, 7] Identical Flow[cite: 7]
Reasoning Prefix (first 12 tokens) "User complains about darkness. set_light..."[cite: 3, 7] "User complains about darkness. set_light..."[cite: 4, 7] Bit-exact Match[cite: 7]
Reasoning Suffix "...to 'on' for better visibility."[cite: 3, 7] "...on to 'on' to reduce brightness."[cite: 4, 7] Float drift (L13)[cite: 7]
Confidence Output 0.0004 (rounded to 4 decimals)[cite: 3, 7] 0.00000417 (raw FP64 post-rollout)[cite: 4, 7] Fully Active[cite: 7]
RAM Footprint ~25 MB (peak_ram_mb: 25.0)[cite: 3, 7] ~35–45 MB[cite: 7] Stable / Zero Crash[cite: 7]

6. Repository File Structure

.
├── index.html               # Web runner, UI, constrained decoding & token cleanup
├── engine-full.js           # Patched Pure-JS runtime (A55 NEON CQ2 & Engram int8 cache)
├── cact-full.js             # Quantized weights parser & loader (.cact)
├── tokenizer-full.js        # Pure-JavaScript SentencePiece tokenizer
├── needle2.cact             # Quantized model weights binary (~13.7 MB)
├── needle2_lan_server.js    # Zero-dependency local LAN HTTP server
├── README.md                # Project documentation
├── reports/                 # Technical Markdown reports & evaluation logs
│   ├── a31-native-complete-oracle.md
│   ├── a54_layer8_diagnostic_report.md
│   └── a55_layer11_cq2_parity_report.md
└── diagnostics/             # Native ARMv7 binaries & Python validation probes (A31-A55)

[cite: 7]


7. Execution Guide

1. Launch LAN Server (Host Machine)

node needle2_lan_server.js . 8000

[cite: 7]

2. Run Inference on Android Device

  1. Connect the mobile device to the same Wi-Fi network as the host machine[cite: 7].
  2. Identify the host IP address (hostname -I)[cite: 7].
  3. Open the browser on the Android phone and navigate to[cite: 7]:
    http://<HOST_IP>:8000/index.html
    

[cite: 7] 4. Input a prompt (e.g., "It's too dark to see." or "Turn the lights on.") and tap Run[cite: 1, 4, 7].


8. Relevant Documentation & Technical Reports (Markdown)

Releases

Packages

Contributors

Languages