id: SMH-RESEARCH-PROTO001
type: research
title: "Prototype Verification Report"
Prototype Verification Report
Generated: 2026-05-22
Status: COMPLETE — all prototypes tested, fixes applied
Environment: rustc 1.95.0, aarch64-unknown-linux (Termux/Android)
Last verified: 2026-05-23 (cargo check + cargo run for all prototypes in report table)
Results
#
Prototype
Status
Summary
P1
Workspace deps (22 crates)
✅ PASS
All deps resolve and compile.
P2
mlua vendored LuaJIT
INACTIVE (SUPERSEDED)
Historical prototype only. Android link failed due to missing compiler-rt builtins; canonical follow-up is P2d.
P2b
mlua non-JIT comparison prototype
✅ SUPERSEDED
Proved mlua sandbox behavior, coroutines, serde, and error propagation on Android. Alternate runtime path removed; P2d is canonical.
P2d
mlua vendored LuaJIT static ARM
✅ PASS
Static vendored LuaJIT works on Android/Termux when linking libclang_rt.builtins-aarch64-android.a for __clear_cache.
P3
CBOR session codec (minicbor)
INACTIVE (SUPERSEDED)
Historical prototype only. Enum derive was broken; canonical replacement is P3b.
P3b
CBOR session codec (ciborium)
✅ PASS
All 4 SessionEntry variants + TraceEntry roundtrip.
P4
ratatui TUI + mouse
✅ PASS
Fixed unused imports. Compiles clean.
P5
Provider trait + MuxProvider
✅ PASS
Fixed with async-trait crate. Failover + circuit breaker work.
P6
Config parsing + CBOR
✅ PASS
Fixed with ciborium. Config roundtrip OK (146 bytes).
P7
zstd trace codec
✅ PASS
Fixed with ciborium+serde. 100 entries, 4.4% compression ratio.
P8
Terminal cap detection
✅ PASS
Fixed with unsafe extern "C". Truecolor, size detection work.
P9
SSE stream parser
✅ PASS
Parse, [DONE], multi-line data all pass.
P10
xtask release (tar/zip/sha256)
✅ PASS
Fixed with SimpleFileOptions. tar.gz + zip + checksums.
P11
Trace roundtrip (CBOR+zstd+header)
✅ PASS
All 7 integration tests: SessionEntry CBOR-seq, TraceEntry CBOR-seq, zstd compress/decompress, length-prefixed (uncompressed + compressed), TraceFileHeader binary, full trace file roundtrip.
P12
Real LLM streaming (MiniMax API)
✅ PASS (live)
Real SSE streaming confirmed with Token Plan endpoint (api.minimax.io/v1/chat/completions, model MiniMax-M2.7). 5 chunks received, content-length finish_reason. Mock SSE also passes.
P13
Harness reload timing
✅ PASS
100 cycles: P50=0.4ms, P99=0.6ms, 2040 reloads/sec. Init+warmup+teardown all sub-ms.
P14
Replay engine validation
✅ PASS
Trace replay semantics, turn seek, speed modes, compare mode, and smart filtering are all validated.
P15
Hot reload
✅ PASS
Plugin load/reload/rollback, session persistence, and trace event continuity are validated.
P16
syntastica syntax highlighting
✅ PASS
9/9 tests on Android/Termux. Rust/Lua/JS/TS highlighting, themes, HTML render, Processor reuse, zero C deps via runtime-c2rust.
P17
VCS SDK + Lua plugins
✅ PASS
smith.vcs.* primitives exposed to Lua. Time-travel, slash commands, and VCS tools implemented as Lua plugins; Rust core stays primitive-only.
clap command matrix, global flags, replay speed semantics, and eval JSON parsing
P20
SM-012
Test tiers, gates, required cases, and evidence coverage checks
Specs Without Dedicated Prototypes
Spec
Reason
(none)
All canonical specs now have dedicated prototype evidence (P18, P19, P20).
Pass rate: 21/21 build+run (active only), 23/23 check (historical total). Historical build+run remains 21/23 (91%) because P2 and P3 are inactive superseded entries. P3 is superseded by P3b (ciborium). P2 is superseded by P2d, which proves vendored static LuaJIT works on Android/Termux.
Switched to ciborium, replaced broken TOML parser with direct JSON.
P7
minicbor enum broken + is_finished()
Rewrote with ciborium+serde. Uses cursor-based CBOR stream decode.
P8
extern "C" blocks need unsafe
Added unsafe keyword.
P10
zip 2.x FileOptions
Changed to SimpleFileOptions::default().
Critical Issues
P0-1: minicbor enum derive broken — switch to ciborium
Spec: SM-005/SM-006 define CBOR session types using minicbor with #[derive(Encode, Decode)]Problem: minicbor-derive generates Encode<Ctx>/Decode<Ctx> for enums where Ctx=() does NOT satisfy. Structs work. Enums fail.
Impact: CBOR session encoding/decoding completely blocked.
Resolution: P3b proves ciborium (serde-based) handles all SessionEntry and TraceEntry enum variants correctly. P6 and P7 also validate ciborium for config and trace encoding.
Spec changes needed:
File
Current
Correct
SM-003
minicbor = { version = "0.25", features = ["std", "derive"] }
ciborium = "0.2" + serde = { version = "1", features = ["derive"] }
SM-011
Same workspace dep change
Same
SM-005
#[derive(minicbor::Encode, minicbor::Decode)] on enums
P0-2: async fn in Provider trait — NOT A SPEC ISSUE
Original claim: SM-007 uses async fn stream(...) which is not dyn-compatible.
Actual: SM-007 uses fn stream(&self, request: ProviderRequest) -> Pin<Box<dyn Stream<Item = ProviderEvent> + Send>>. This IS dyn-compatible — no async-trait needed in the spec.
Resolution: P5 prototype used async fn as a simplified design choice, but the actual spec already uses the correct Pin<Box<dyn Stream>> pattern. No spec change needed.
P0-3: mlua 0.10 load() API — NOT A SPEC ISSUE
Original claim: SM-009 uses lua.load(code, None) (two args) which fails in mlua 0.10.
Actual: SM-009 already uses lua.load(&source).eval()? — the correct single-arg API.
Resolution: Prototype P2's original code used the old API and was fixed. The spec is already correct. No spec change needed.
Spec: SM-009 specifies mlua = { features = ["luajit", "vendored"] }Problem: LuaJIT's JIT compiler calls __clear_cache; Rust's Android link path did not include compiler-rt builtins.
Impact: Original P2 failed to link on Android/Termux.
Resolution: P2d proves vendored static LuaJIT works on Android/Termux when linking libclang_rt.builtins-aarch64-android.a.
Required link input: add Android target rustflags or build-script detection for compiler-rt builtins, e.g. -lclang_rt.builtins-aarch64-android.
Spec change: None to Lua runtime choice. Keep single canonical runtime: mlua + vendored LuaJIT.
Moderate Issues
P2-1: extern "C" blocks require unsafe
Spec: SM-008 termcap detection uses extern "C" { fn isatty(...) -> i32; }Problem: Rust 2024 edition requires unsafe extern "C" { ... }.
Fix: Add unsafe keyword. Or use libc::isatty().
Spec change: SM-008 — use libc::isatty() instead of raw FFI.
P2-2: zip 2.x start_file type change — NOT A SPEC ISSUE
Original claim: SM-003 uses FileOptions::default() which is removed in zip 2.x.
Actual: SM-003 already uses zip::write::SimpleFileOptions::default().
Resolution: Prototype P10's original code used the old API and was fixed. The spec is already correct.
Problem: minicbor-derive, serde_derive, and async-trait generate code that may trigger warnings. -D warnings in workspace Cargo.toml applies to all crates.
Fix: #[allow(dead_code)] on enums with unused variants, #![allow(...)] in crate roots.
Spec change: .system/RULES.md — document #[allow] strategy for proc-macro output.
P2-4: P5 unused dependencies (FIXED)
Problem: P5 Cargo.toml included 4 unused deps: reqwest, futures, serde_json, uuid. Adds unnecessary compile time.
Impact: Minor bloat in prototype. Not a design issue — real smith-ai may use reqwest.
Fix applied: Removed all 4 unused deps. Verified clean build.
Spec Corrections Summary
Priority
Issue
Specs Affected
Action
P0
Switch minicbor → ciborium
SM-003, SM-005, SM-006, SM-004, SM-011
Replace CBOR crate and all Encode/Decode usage
P0
LuaJIT vendored on Android
SM-003, SM-011
RESOLVED by P2d: link compiler-rt builtins; keep vendored LuaJIT only
P0
Provider trait async dyn
SM-003, SM-007
NOT A SPEC ISSUE — spec uses Pin<Box>
P0
mlua 0.10 load() API
SM-009
NOT A SPEC ISSUE — spec already correct
P2
extern "C" unsafe
SM-008
NOT A SPEC ISSUE — spec uses crossterm
P2
zip 2.x API
SM-003
NOT A SPEC ISSUE — spec already correct
P2
Zero-warnings + macros
.system/RULES.md
Document #[allow] strategy
Verified Working
Component
Crate
Version
Verified By
mlua + LuaJIT (vendored)
mlua
0.10.5
P2d ✅ static on Android/Termux with compiler-rt builtins link
Full trace file roundtrip (header + compressed body)
Key finding: Per-entry zstd compression is 115.5% of raw CBOR for small traces (4 entries). The spec claims "60-70% size reduction" but that only applies to larger traces with more repetitive data. Small entries have too much zstd header overhead per entry.
Recommendation: Consider block-level compression (compress N entries together) for traces with < 50 entries, and per-entry compression for larger traces. Or use a minimum entry size threshold before compressing.
P12: Real LLM Streaming
What it tests: reqwest HTTP client + SSE stream parsing + JSON deserialization + error handling.
Mock SSE test passes: 4 chunks parsed, content="Hello world", finish_reason=stop.
Real API test: MiniMax Token Plan endpoint confirmed working. api.minimax.io/v1/chat/completions, model MiniMax-M2.7. HTTP 200 + content-type: text/event-stream. Received 5 SSE chunks, finish_reason=length (hit max_tokens=50). Full content received.
Key finding: Harness reload is extremely fast — 0.4ms median. Lua runtime init is 0.2ms P50, CBOR config roundtrip is sub-ms. Fast enough for hot-reload on plugin change without perceptible delay. No need for lazy init or connection pooling for the Lua subsystem.
P16: Syntax Highlighting (syntastica)
What it tests: syntastica with runtime-c2rust on Android/Termux, exercising Rust/Lua/JavaScript/TypeScript highlighting, theme switching, custom themes, file type detection, Processor reuse, and HTML output.
Key findings:
runtime-c2rust avoids C runtime dependencies; no Oniguruma or libtree-sitter dynamic link.
Terminal truecolor ANSI output and HTML rendering both work.
TOML support is not required for v1; use explicit language selection where file type detection is incomplete.
P17: VCS SDK + Lua Plugins
What it tests: Rust exposes only smith.vcs.* and smith.shortcut.* primitives through mlua; features are Lua plugins.
All feature flows pass through Lua plugins:
time-travel.lua — timeline/op inspection/diff/undo flow over smith.vcs.*.
Architectural rule holds: built-in features are Lua plugins; Rust core provides minimal primitives.
jj operation history can back undo/redo and time-travel without custom file snapshot stacks.
Plugin-facing VCS APIs need validated inputs, structured outputs, and mode-aware shortcuts.
Recommendations
Accept ciborium over minicbor — Proven in 3 prototypes (P3b, P6, P7). Eliminates all minicbor-related issues. Adds serde dependency (already needed for JSON config). Tradeoff: slightly larger binary, no zero-copy decode. Acceptable.
Use one Lua runtime path — P2d proves mlua with luajit + vendored compiles, links, and runs on Android/Termux when compiler-rt builtins are linked. Keep LuaJIT as the only supported runtime path; remove alternate runtime features.
Document #[allow] strategy — Proc-macro derive output (serde, ciborium) may trigger warnings under -D warnings policy. Create a .system/RULES.md section on allow-lint strategy.
Revisit zstd per-entry compression — P11 shows per-entry zstd is 115% of raw CBOR for small traces. Consider block-level compression or minimum entry size threshold. Update SM-006 §13.3 compression trade-off note.
Handle non-SSE error responses — P12 shows MiniMax returns errors as plain JSON (HTTP 200) not SSE. SM-007 Provider implementations must detect non-streaming JSON and convert to ProviderEvent::Error.
Keep Rust core primitive-only — P17 validates the target architecture: Rust exposes SDK primitives (smith.vcs.*, smith.shortcut.*, smith.tui.*), while user-facing features are Lua plugins. Built-in plugins and user plugins must use the same interface.
The following were initially flagged but verified as NOT spec issues:
- Add async-trait crate (SM-007 already uses Pin<Box>)- Fix mlua load() API (SM-009 already uses correct single-arg form)- Use libc for FFI (SM-008 uses crossterm, not raw extern "C")- Update zip API (SM-003 already uses SimpleFileOptions)
Post-Audit Fixes
Audit Fix 1: P6 mlua dead dependency (APPLIED)
Found: P6 Cargo.toml listed mlua = { version = "0.10", features = ["luajit", "vendored", "serialize"] } but source never used mlua. Vendored LuaJIT fails to link on Android/Termux (same __clear_cache as P2).
Impact: P6 could not build on this platform despite code being correct.
Fix applied: Removed mlua from P6 Cargo.toml. Verified clean build.
Audit Fix 2: P5 unused dependencies (APPLIED)
Found: P5 Cargo.toml had 4 unused deps: futures, reqwest, serde_json, uuid. Report only flagged reqwest.
Fix applied: Removed all 4. Verified clean build.
---
id: SMH-RESEARCH-PROTO001
type: research
title: "Prototype Verification Report"
---
# Prototype Verification Report
**Generated**: 2026-05-22
**Status**: COMPLETE — all prototypes tested, fixes applied
**Environment**: rustc 1.95.0, aarch64-unknown-linux (Termux/Android)
**Last verified**: 2026-05-23 (cargo check + cargo run for all prototypes in report table)
## Results
| # | Prototype | Status | Summary |
|---|-----------|--------|---------|
| P1 | Workspace deps (22 crates) | ✅ PASS | All deps resolve and compile. |
| P2 | mlua vendored LuaJIT | INACTIVE (SUPERSEDED) | Historical prototype only. Android link failed due to missing compiler-rt builtins; canonical follow-up is P2d. |
| P2b | mlua non-JIT comparison prototype | ✅ SUPERSEDED | Proved mlua sandbox behavior, coroutines, serde, and error propagation on Android. Alternate runtime path removed; P2d is canonical. |
| P2d | mlua vendored LuaJIT static ARM | ✅ PASS | Static vendored LuaJIT works on Android/Termux when linking `libclang_rt.builtins-aarch64-android.a` for `__clear_cache`. |
| P3 | CBOR session codec (minicbor) | INACTIVE (SUPERSEDED) | Historical prototype only. Enum derive was broken; canonical replacement is P3b. |
| P3b | CBOR session codec (ciborium) | ✅ PASS | All 4 SessionEntry variants + TraceEntry roundtrip. |
| P4 | ratatui TUI + mouse | ✅ PASS | Fixed unused imports. Compiles clean. |
| P5 | Provider trait + MuxProvider | ✅ PASS | Fixed with async-trait crate. Failover + circuit breaker work. |
| P6 | Config parsing + CBOR | ✅ PASS | Fixed with ciborium. Config roundtrip OK (146 bytes). |
| P7 | zstd trace codec | ✅ PASS | Fixed with ciborium+serde. 100 entries, 4.4% compression ratio. |
| P8 | Terminal cap detection | ✅ PASS | Fixed with `unsafe extern "C"`. Truecolor, size detection work. |
| P9 | SSE stream parser | ✅ PASS | Parse, [DONE], multi-line data all pass. |
| P10 | xtask release (tar/zip/sha256) | ✅ PASS | Fixed with `SimpleFileOptions`. tar.gz + zip + checksums. |
| P11 | Trace roundtrip (CBOR+zstd+header) | ✅ PASS | All 7 integration tests: SessionEntry CBOR-seq, TraceEntry CBOR-seq, zstd compress/decompress, length-prefixed (uncompressed + compressed), TraceFileHeader binary, full trace file roundtrip. |
| P12 | Real LLM streaming (MiniMax API) | ✅ PASS (live) | Real SSE streaming confirmed with Token Plan endpoint (`api.minimax.io/v1/chat/completions`, model `MiniMax-M2.7`). 5 chunks received, content-length finish_reason. Mock SSE also passes. |
| P13 | Harness reload timing | ✅ PASS | 100 cycles: P50=0.4ms, P99=0.6ms, 2040 reloads/sec. Init+warmup+teardown all sub-ms. |
| P14 | Replay engine validation | ✅ PASS | Trace replay semantics, turn seek, speed modes, compare mode, and smart filtering are all validated. |
| P15 | Hot reload | ✅ PASS | Plugin load/reload/rollback, session persistence, and trace event continuity are validated. |
| P16 | syntastica syntax highlighting | ✅ PASS | 9/9 tests on Android/Termux. Rust/Lua/JS/TS highlighting, themes, HTML render, Processor reuse, zero C deps via `runtime-c2rust`. |
| P17 | VCS SDK + Lua plugins | ✅ PASS | `smith.vcs.*` primitives exposed to Lua. Time-travel, slash commands, and VCS tools implemented as Lua plugins; Rust core stays primitive-only. |
| P18 | Architecture contract | ✅ PASS | Data-only crate graph, dependency boundaries, ownership map, and async boundaries verified. |
| P19 | CLI smoke | ✅ PASS | SM-010 subcommand coverage and parsing behavior verified with clap. |
| P20 | Testing methodology meta | ✅ PASS | SM-012 coverage gates, tier gates, and evidence mapping checks are codified and validated. |
| **Total** | **23 prototypes** (incl. 2 inactive historical) | **21/21 active build+run** | **100% active build+run, 91% historical build+run, 23/23 historical check** |
## Prototype → Spec Mapping
| Prototype | Spec(s) Covered | Aspect Verified |
|-----------|----------------|----------------|
| P1 | SM-003 | Workspace deps (22 crates) resolve & compile |
| P2 | SM-009 | Historical/inactive superseded: original LuaJIT attempt (archived only) |
| P2b | SM-009 | Historical/inactive superseded non-JIT sandbox behavior comparison |
| P2d | SM-009 | Canonical vendored static LuaJIT on ARM/Android with compiler-rt builtins link |
| P3 | SM-005, SM-006 | Historical/inactive superseded: minicbor enum derivation attempt |
| P3b | SM-005, SM-006 | Canonical proof for CBOR codec using ciborium (SessionEntry/TraceEntry) |
| P4 | SM-008 | ratatui + crossterm TUI, mouse events |
| P5 | SM-007 | Provider trait, async dyn, MuxProvider failover + circuit breaker |
| P6 | SM-005 | Config parsing (SmithConfig structure) + CBOR roundtrip |
| P7 | SM-006 | zstd compressed trace codec, CBOR stream decode |
| P8 | SM-008 | Terminal cap detection (isatty, truecolor, size) |
| P9 | SM-007 | SSE stream parser, [DONE], multi-line data |
| P10 | SM-003, SM-011 | xtask release build (tar/zip/sha256) |
| P11 | SM-005, SM-006 | CBOR+zstd trace codec integration (SessionEntry + TraceEntry + TraceFileHeader roundtrip) |
| P12 | SM-007 | Real LLM API streaming (reqwest + SSE parse, Token Plan endpoint) |
| P13 | SM-009 | Harness init/warmup/teardown reload timing (Lua + CBOR + config) |
| P16 | SM-008 | Syntax highlighting with syntastica (`runtime-c2rust`), themes, file type detection, terminal/HTML render |
| P17 | SM-006, SM-009, SM-010 | VCS primitives (`smith.vcs.*`) plus Lua plugins for time-travel, `/undo`/`/redo`, and VCS tools |
| P14 | SM-006 | Replay engine behavior and session reconstruction |
| P15 | SM-009 | Hot reload lifecycle, rollback, and session continuity |
| P18 | SM-004 | Crate graph, ownership map, plugin-only feature ownership, async boundary assertions |
| P19 | SM-010 | clap command matrix, global flags, replay speed semantics, and eval JSON parsing |
| P20 | SM-012 | Test tiers, gates, required cases, and evidence coverage checks |
### Specs Without Dedicated Prototypes
| Spec | Reason |
|------|--------|
| *(none)* | All canonical specs now have dedicated prototype evidence (P18, P19, P20). |
**Pass rate**: **21/21 build+run** (active only), **23/23 check** (historical total). Historical build+run remains 21/23 (91%) because P2 and P3 are inactive superseded entries. P3 is superseded by P3b (ciborium). P2 is superseded by P2d, which proves vendored static LuaJIT works on Android/Termux.
**Integration prototypes** (P11, P12, P17) cross subsystem boundaries:
- P11 validates SM-005 shared types + SM-006 core TraceCodec work together end-to-end
- P12 validates SM-007 Provider network I/O with SSE parsing (mock-verified, real API needs valid key)
- P17 validates SM-009 Lua plugin features over SM-006/SM-010 VCS/session primitives
- P18 validates SM-004 canonical architecture boundaries
- P19 validates SM-010 CLI surface and argument behavior
- P20 validates SM-012 testing gates and required case coverage
---
## Fixes Applied
| Prototype | Original Issue | Fix Applied |
|-----------|---------------|-------------|
| P2 | `lua.load(code, None)` — 2 args | `lua.load(code)` — 1 arg (mlua 0.10 API). Linker still fails on Android. |
| P4 | Unused imports `KeyEvent`, `MouseEvent`, `Clear` | Removed from use statements. |
| P5 | `async fn` in trait not dyn-compatible | Added `async-trait = "0.1"` crate + `#[async_trait]` annotation. |
| P6 | minicbor enum broken + unused vars | Switched to ciborium, replaced broken TOML parser with direct JSON. |
| P7 | minicbor enum broken + `is_finished()` | Rewrote with ciborium+serde. Uses cursor-based CBOR stream decode. |
| P8 | `extern "C"` blocks need `unsafe` | Added `unsafe` keyword. |
| P10 | zip 2.x `FileOptions` | Changed to `SimpleFileOptions::default()`. |
---
## Critical Issues
### P0-1: minicbor enum derive broken — switch to ciborium
**Spec**: SM-005/SM-006 define CBOR session types using minicbor with `#[derive(Encode, Decode)]`
**Problem**: minicbor-derive generates `Encode<Ctx>`/`Decode<Ctx>` for enums where `Ctx=()` does NOT satisfy. Structs work. Enums fail.
**Impact**: CBOR session encoding/decoding completely blocked.
**Resolution**: P3b proves ciborium (serde-based) handles all SessionEntry and TraceEntry enum variants correctly. P6 and P7 also validate ciborium for config and trace encoding.
**Spec changes needed**:
| File | Current | Correct |
|------|---------|--------|
| SM-003 | `minicbor = { version = "0.25", features = ["std", "derive"] }` | `ciborium = "0.2"` + `serde = { version = "1", features = ["derive"] }` |
| SM-011 | Same workspace dep change | Same |
| SM-005 | `#[derive(minicbor::Encode, minicbor::Decode)]` on enums | `#[derive(serde::Serialize, serde::Deserialize)]` |
| SM-006 | `minicbor::to_vec(val)` / `minicbor::decode(&buf)` | `ciborium::ser::into_writer(val, &mut buf)` / `ciborium::de::from_reader(&buf[..])` |
| SM-006 | `#[cbor(n(0))]` field annotations | Plain serde — field order determines encoding |
### ~~P0-2~~: `async fn` in Provider trait — NOT A SPEC ISSUE
**Original claim**: SM-007 uses `async fn stream(...)` which is not dyn-compatible.
**Actual**: SM-007 uses `fn stream(&self, request: ProviderRequest) -> Pin<Box<dyn Stream<Item = ProviderEvent> + Send>>`. This IS dyn-compatible — no async-trait needed in the spec.
**Resolution**: P5 prototype used `async fn` as a simplified design choice, but the actual spec already uses the correct `Pin<Box<dyn Stream>>` pattern. No spec change needed.
### ~~P0-3~~: mlua 0.10 `load()` API — NOT A SPEC ISSUE
**Original claim**: SM-009 uses `lua.load(code, None)` (two args) which fails in mlua 0.10.
**Actual**: SM-009 already uses `lua.load(&source).eval()?` — the correct single-arg API.
**Resolution**: Prototype P2's original code used the old API and was fixed. The spec is already correct. No spec change needed.
### P0-4: LuaJIT vendored Android/Termux linker issue — RESOLVED
**Spec**: SM-009 specifies `mlua = { features = ["luajit", "vendored"] }`
**Problem**: LuaJIT's JIT compiler calls `__clear_cache`; Rust's Android link path did not include compiler-rt builtins.
**Impact**: Original P2 failed to link on Android/Termux.
**Resolution**: P2d proves vendored static LuaJIT works on Android/Termux when linking `libclang_rt.builtins-aarch64-android.a`.
**Required link input**: add Android target rustflags or build-script detection for compiler-rt builtins, e.g. `-lclang_rt.builtins-aarch64-android`.
**Spec change**: None to Lua runtime choice. Keep single canonical runtime: `mlua` + vendored LuaJIT.
---
## Moderate Issues
### P2-1: `extern "C"` blocks require `unsafe`
**Spec**: SM-008 termcap detection uses `extern "C" { fn isatty(...) -> i32; }`
**Problem**: Rust 2024 edition requires `unsafe extern "C" { ... }`.
**Fix**: Add `unsafe` keyword. Or use `libc::isatty()`.
**Spec change**: SM-008 — use `libc::isatty()` instead of raw FFI.
### ~~P2-2~~: zip 2.x `start_file` type change — NOT A SPEC ISSUE
**Original claim**: SM-003 uses `FileOptions::default()` which is removed in zip 2.x.
**Actual**: SM-003 already uses `zip::write::SimpleFileOptions::default()`.
**Resolution**: Prototype P10's original code used the old API and was fixed. The spec is already correct.
### P2-3: Zero-warnings policy + third-party derive macros
**Problem**: minicbor-derive, serde_derive, and async-trait generate code that may trigger warnings. `-D warnings` in workspace Cargo.toml applies to all crates.
**Fix**: `#[allow(dead_code)]` on enums with unused variants, `#![allow(...)]` in crate roots.
**Spec change**: .system/RULES.md — document `#[allow]` strategy for proc-macro output.
### P2-4: P5 unused dependencies (FIXED)
**Problem**: P5 `Cargo.toml` included 4 unused deps: `reqwest`, `futures`, `serde_json`, `uuid`. Adds unnecessary compile time.
**Impact**: Minor bloat in prototype. Not a design issue — real smith-ai may use reqwest.
**Fix applied**: Removed all 4 unused deps. Verified clean build.
---
## Spec Corrections Summary
| Priority | Issue | Specs Affected | Action |
|----------|-------|---------------|--------|
| P0 | Switch minicbor → ciborium | SM-003, SM-005, SM-006, SM-004, SM-011 | Replace CBOR crate and all Encode/Decode usage |
| P0 | LuaJIT vendored on Android | SM-003, SM-011 | RESOLVED by P2d: link compiler-rt builtins; keep vendored LuaJIT only |
| ~~P0~~ | ~~Provider trait async dyn~~ | ~~SM-003, SM-007~~ | ~~NOT A SPEC ISSUE — spec uses Pin<Box<dyn Stream>>~~ |
| ~~P0~~ | ~~mlua 0.10 load() API~~ | ~~SM-009~~ | ~~NOT A SPEC ISSUE — spec already correct~~ |
| ~~P2~~ | ~~extern "C" unsafe~~ | ~~SM-008~~ | ~~NOT A SPEC ISSUE — spec uses crossterm~~ |
| ~~P2~~ | ~~zip 2.x API~~ | ~~SM-003~~ | ~~NOT A SPEC ISSUE — spec already correct~~ |
| P2 | Zero-warnings + macros | .system/RULES.md | Document #[allow] strategy |
---
## Verified Working
| Component | Crate | Version | Verified By |
|-----------|-------|---------|-------------|
| mlua + LuaJIT (vendored) | mlua | 0.10.5 | P2d ✅ static on Android/Termux with compiler-rt builtins link |
| mlua non-JIT comparison prototype | mlua | 0.10.5 | P2b ✅ behavior proven, superseded by P2d |
| ratatui + crossterm | ratatui | 0.29.0 | P4 ✅ |
| crossterm | crossterm | 0.28.1 | P4, P8 ✅ |
| ciborium (serde CBOR) | ciborium | 0.2.2 | P3b, P6, P7 ✅ |
| async-trait | async-trait | 0.1 | P5 ✅ |
| SSE parser (hand-rolled) | — | — | P9 ✅ |
| tar.gz / zip / sha256 | tar, zip, sha2 | 0.4, 2.x, 0.10 | P10 ✅ |
| tokio async runtime | tokio | 1.x | P5 ✅ |
| thiserror | thiserror | 2 | P5, P6 ✅ |
| zstd compression | zstd | 0.13 | P7 ✅ (4.4% ratio) |
| flate2 gzip | flate2 | 1.x | P10 ✅ |
| serde JSON roundtrip | serde_json | 1.x | P6 ✅ |
---
## Integration Prototype Findings
### P11: Trace Roundtrip (CBOR + zstd + TraceFileHeader)
**What it tests**: SM-005 SessionEntry enum + SM-006 TraceEntry enum + TraceFileHeader binary layout + zstd compression + length-prefixed CBOR-seq encoding.
**All 7 tests pass:**
1. SessionEntry CBOR-seq roundtrip (6 variants, 655 bytes)
2. TraceEntry CBOR-seq roundtrip (4 entries, 335 bytes)
3. zstd compress/decompress (69.0% ratio)
4. Length-prefixed encoding (uncompressed)
5. Length-prefixed encoding (per-entry zstd compressed)
6. TraceFileHeader binary write/read (64 bytes)
7. Full trace file roundtrip (header + compressed body)
**Key finding**: Per-entry zstd compression is **115.5% of raw CBOR** for small traces (4 entries). The spec claims "60-70% size reduction" but that only applies to larger traces with more repetitive data. Small entries have too much zstd header overhead per entry.
**Recommendation**: Consider block-level compression (compress N entries together) for traces with < 50 entries, and per-entry compression for larger traces. Or use a minimum entry size threshold before compressing.
### P12: Real LLM Streaming
**What it tests**: reqwest HTTP client + SSE stream parsing + JSON deserialization + error handling.
**Mock SSE test passes**: 4 chunks parsed, content="Hello world", finish_reason=stop.
**Real API test**: MiniMax Token Plan endpoint confirmed working. `api.minimax.io/v1/chat/completions`, model `MiniMax-M2.7`. HTTP 200 + `content-type: text/event-stream`. Received 5 SSE chunks, `finish_reason=length` (hit max_tokens=50). Full content received.
**Key findings**:
- Token Plan uses `api.minimax.io` (NOT `api.minimax.chat`). Key prefix `sk-cp-` = Token Plan.
- Model `MiniMax-M2.7` replaces deprecated `MiniMax-Text-01`.
- Endpoint is OpenAI-compatible `/v1/chat/completions`.
- MiniMax returns errors as non-streaming JSON with HTTP 200 — error detection must check body format.
**Verified working:**
- reqwest streaming (bytes_stream)
- SSE line parsing (event:, data:, multi-line, [DONE])
- ChatCompletion JSON deserialization
- Real Token Plan authentication
### P13: Harness Reload Timing
**What it tests**: SM-009 harness integration — init/teardown/reinit cycle timing for Lua runtime + CBOR codec + config + provider registry.
**All 6 tests pass:**
1. Harness init: 0.9ms (first run)
2. Warmup (sandbox + 2 plugin stubs + CBOR encode): 0.3ms
3. Verify operational (Lua eval + config + codec + providers)
4. Teardown (drop): 0.1ms
5. 100 consecutive reload cycles
6. Statistics + assertions
**Results (100 cycles on Android/Termux aarch64):**
| Metric | Value |
|--------|-------|
| P50 reload | 0.4ms |
| P95 reload | 0.5ms |
| P99 reload | 0.6ms |
| Throughput | 2040 reloads/sec |
| Total 100 cycles | 49.0ms |
**Key finding**: Harness reload is extremely fast — 0.4ms median. Lua runtime init is 0.2ms P50, CBOR config roundtrip is sub-ms. Fast enough for hot-reload on plugin change without perceptible delay. No need for lazy init or connection pooling for the Lua subsystem.
---
## P16: Syntax Highlighting (syntastica)
**What it tests**: syntastica with `runtime-c2rust` on Android/Termux, exercising Rust/Lua/JavaScript/TypeScript highlighting, theme switching, custom themes, file type detection, Processor reuse, and HTML output.
**Key findings**:
- `runtime-c2rust` avoids C runtime dependencies; no Oniguruma or `libtree-sitter` dynamic link.
- Terminal truecolor ANSI output and HTML rendering both work.
- TOML support is not required for v1; use explicit language selection where file type detection is incomplete.
---
## P17: VCS SDK + Lua Plugins
**What it tests**: Rust exposes only `smith.vcs.*` and `smith.shortcut.*` primitives through mlua; features are Lua plugins.
**All feature flows pass through Lua plugins:**
1. `time-travel.lua` — timeline/op inspection/diff/undo flow over `smith.vcs.*`.
2. `commands.lua` — `/undo`, `/redo`, history commands.
3. `vcs-tools.lua` — status, diff, history, restore, annotate-style tool surfaces.
**Key findings**:
- Architectural rule holds: built-in features are Lua plugins; Rust core provides minimal primitives.
- jj operation history can back undo/redo and time-travel without custom file snapshot stacks.
- Plugin-facing VCS APIs need validated inputs, structured outputs, and mode-aware shortcuts.
---
## Recommendations
1. **Accept ciborium over minicbor** — Proven in 3 prototypes (P3b, P6, P7). Eliminates all minicbor-related issues. Adds serde dependency (already needed for JSON config). Tradeoff: slightly larger binary, no zero-copy decode. Acceptable.
2. **Use one Lua runtime path** — P2d proves `mlua` with `luajit` + `vendored` compiles, links, and runs on Android/Termux when compiler-rt builtins are linked. Keep LuaJIT as the only supported runtime path; remove alternate runtime features.
3. **Document `#[allow]` strategy** — Proc-macro derive output (serde, ciborium) may trigger warnings under `-D warnings` policy. Create a .system/RULES.md section on allow-lint strategy.
4. **Revisit zstd per-entry compression** — P11 shows per-entry zstd is 115% of raw CBOR for small traces. Consider block-level compression or minimum entry size threshold. Update SM-006 §13.3 compression trade-off note.
5. **Handle non-SSE error responses** — P12 shows MiniMax returns errors as plain JSON (HTTP 200) not SSE. SM-007 Provider implementations must detect non-streaming JSON and convert to `ProviderEvent::Error`.
6. **Keep Rust core primitive-only** — P17 validates the target architecture: Rust exposes SDK primitives (`smith.vcs.*`, `smith.shortcut.*`, `smith.tui.*`), while user-facing features are Lua plugins. Built-in plugins and user plugins must use the same interface.
~~The following were initially flagged but verified as NOT spec issues:~~
~~- Add async-trait crate (SM-007 already uses Pin<Box<dyn Stream>>)~~
~~- Fix mlua load() API (SM-009 already uses correct single-arg form)~~
~~- Use libc for FFI (SM-008 uses crossterm, not raw extern "C")~~
~~- Update zip API (SM-003 already uses SimpleFileOptions)~~
---
## Post-Audit Fixes
### Audit Fix 1: P6 mlua dead dependency (APPLIED)
**Found**: P6 `Cargo.toml` listed `mlua = { version = "0.10", features = ["luajit", "vendored", "serialize"] }` but source never used mlua. Vendored LuaJIT fails to link on Android/Termux (same `__clear_cache` as P2).
**Impact**: P6 could not build on this platform despite code being correct.
**Fix applied**: Removed mlua from P6 Cargo.toml. Verified clean build.
### Audit Fix 2: P5 unused dependencies (APPLIED)
**Found**: P5 `Cargo.toml` had 4 unused deps: `futures`, `reqwest`, `serde_json`, `uuid`. Report only flagged `reqwest`.
**Fix applied**: Removed all 4. Verified clean build.