Date: 2026-04-14 (addenda 2026-07-03, 2026-07-06) Status: Research prototype — methodology now proven on a whole library end-to-end and a second, never-seen library, autonomously. Still NOT a one-command tool for arbitrary C.
Large jumps since the 2026-07-03 addendum below. Several of that report's core claims are now superseded (noted inline); the honest framing still holds.
The 2026-07-03 report said "compress/uncompress/inflate/deflate remain
non-functional stubs." No longer true. zlib deflate and inflate are
translated to pure safe Rust and verified byte-identical to the C reference:
deflatebyte-exact at levels 1–9 +Z_HUFFMAN_ONLY+Z_RLEinflatebyte-exact on stored / dynamic / fixed Huffman streams (LZ77 back-refs)- Full round-trip
Rust deflate → Rust inflate → originalbyte-identical: 21/21 across levels 1/6/9, plus 8/8 large-input (50–90 KB) stress, both raw and the standard zlib format (header + adler32 validated). Zerounsafe. - The whole ~30-state
inflate()machine,goto, unions, pointer aliasing, and bit-twiddling re-expressed in safe Rust. Seedocs/zlib_case_study.md.
The differential oracle caught ~9 real integration bugs unit tests passed clean over — the correctness engine works.
Scope note (2026-07-06): the
alchemist/autonomy/track below is ORPHANED — the shipping CLI does not use it, and most of it duplicates more-mature shipping modules. Only four items are genuinely new (Miri gate — now promoted to the verifier--mirigate; sanitizer-diff; perf parity;shim_synth). See docs/GROUNDING.md. New workstreams (alchemist/autonomy/,alchemist/catalog/), all tested:
- WS4 diagnose-and-repair loop — stub → model refill from C → differential
gate → iterate on the exact discrepancy → verify-or-revert → refuse (never
fake-green). Proven live: repaired an injected
adler32_zbug autonomously. - WS1 shim synthesis — auto-generates the mechanical oracle glue from a
struct's fields (library-agnostic via
c_struct.py), compile-validated. - WS2 type-model inference — infers the coherent owned-Rust type model from a
C struct (pointers→
Vec, indices→usize, back-refs flagged) — reproduced 10/10 zlib decisions from the header alone. - WS6 idiom catalog —
C→safe-Rustpatterns injected per function by signal. - M1 autonomy scorecard — a real metric. 100 items autonomously retired
(26 functions differential-proven + 74 oracle shims compile-validated); open
debt 227 → 127. Every retirement has a proof in
retired_ledger.json.
Pointed the agnostic stack at jsmn (a JSON tokenizer never seen before) with
zero jsmn-specific code: struct-parse → type-infer → coherent signatures → C
reference oracle → the model filled all 6 functions from C → differential-repair
→ 13/13 byte-exact token streams vs C. First end-to-end autonomous
translation of a new library. The one hard function cracked not by brute force
but by diagnosis — reading the model's output vs the C found a single
coherent-model bug (loop cursor increment placement), fixed first-try once named
and captured as a reusable idiom. See docs/m2_jsmn_first_swing.md.
- Does: the methodology is proven on a whole hard library (zlib, byte-exact) AND a second never-seen library (jsmn, autonomous); the engines are agnostic and measured; "hard-frontier" functions are usually diagnosable mismatches, not model ceilings.
- Does NOT: make it one-command for arbitrary C. Still needs WS3 (auto
control-flow structuring for goto/state-machines), WS5 (build/harness
detection), the custom-shim tail, and human confirmation of WS2 review flags.
zlib still has 127 open debt items (the hard stateful tail). See
docs/PATH_TO_AUTONOMY.mdfor the honest milestone ladder (M0✅ → M1 → M5).
What changed since the report below was written:
- The automated differential path produced its first genuine green.
alchemist verify subjects/zlib -p zlib-checksumbuilds the C reference DLL, generates FFI bindings and c_/rust_ adapter wrappers against the actual generated API (discovered from source, not assumed), and runs adler32 + crc32 through 5000 random inputs each against C zlib: 17/17 differential tests pass with zero hand-editing. Previously the emitted diff crate could not even compile (empty lib.rs, orphaned wrappers, missing path-deps). - crc32's big-endian word braid is fixed at all three layers. The
generated
crc_word_big, the pure-Python fuzz reference, and the locked-in regression invariant all implemented (different) wrong variants; all now implement zlib's W=8 configuration, anchored against zlib's shipped crc32.h table values. zlib-checksum: 183/183 tests pass (was 166/17). - Two soundness holes closed. Unhandled algorithm categories used to fall
through to a smoke-only "check" that never consulted the C reference —
they now emit a failing UNVERIFIABLE harness. The test emitter used to
mangle
Some(18usize)intob"Some(18usize)", which broke compilation of the whole zlib-compression test module and vacuously skipped its gate — expected values are now rendered against the function's return type, and those 20 tests compile, run, and honestly FAIL against the stub impls. - A semantic-lint gate now fails closed on wrong algorithm variants.
scan_workspace_semanticssweeps every generated fn against its spec at verify time; a deliberately-wrong CRC braid variant fails the gate (proven by negative test). This is the first real defense against the #1 failure mode (multi-variant disambiguation) for code that compiles and passes vector tests derived from the same wrong assumption.
What did NOT change: verify for the full zlib workspace still fails —
correctly — on 42 anti-stub violations (6 of them in zlib-checksum itself:
make_crc_table, braid, get_crc_table, and the other table-generation
helpers are still skeletons) and on the 20 now-honest zlib-compression test
failures. compress/uncompress/inflate/deflate remain non-functional stubs.
Verified-equivalent today: adler32_z and crc32 (byte-at-a-time public
API), via the automated differential oracle; crc_word_big via fixed
vectors against the corrected pure reference (it is local in C — not
FFI-observable).
alchemist verify subjects/zlib -p zlib-checksum→OVERALL: PASS— the first fully green verification in the project's history. The six table-generation skeletons are now real ports (including a completeinflate_tableport whose generated inffixed.h matches zlib's shipped file byte-for-byte), anchored againstcrc32.h, so the anti-stub gate is clean; test gate 177/0; differential 19/19 incl. new boundary-length tests at NMAX/word/braid fold edges.- The statics now have a compiled-C oracle. A checksum shim DLL
(amalgamated
crc32.c, W=8/N=5 compile-time-pinned) exportscrc_word,crc_word_big,multmodp,x2nmodp; their fuzz vectors regenerate from real compiled zlib and a fail-closed cross-check halts generation on any shim-vs-reference disagreement. This independently confirms the W=8 braid fix against the actual C (crc_word_big(1) == 0x9630077700000000). - Claims are artifacts now. Verify runs emit a content-addressed receipt (gates, bindings, case counts, gcc version, source/DLL hashes).
- Compression is honestly red, not unresolvable. The deflate harness adapts to the real generated API (3/3 harnesses) and its 10 tests fail against the stubs while the 19 checksum tests remain visible.
- Fuzz vectors are now persisted into spec checkpoints with oracle provenance tags and always regenerate when their oracle changes.
Alchemist successfully translated zlib (23,139 lines C → 2,512 lines Rust) with 0 unsafe blocks across 7 compiling crates. Differential testing against C zlib then revealed that most of the generated code is functionally non-operational — it compiles cleanly but doesn't actually do what the C code does.
This report catalogs every bug found, defines what Alchemist needs to be a turnkey C-to-Rust system, and prioritizes the work to get there.
- Stages 1-3 produce high-quality output: tree-sitter analysis, per-function spec extraction, architecture design with proper crate boundaries
- Stage 4 produces compilable output: After Phase 1 fixes (scrubber, holistic fixer, validator), 7/7 crates compile with 0 unsafe
- Adler-32: After fixing wrong constants, bit-exact match with C zlib across 30,000+ random byte arrays
- The methodology is sound: algorithm-first translation produces 9.2× LOC compression and clean idiomatic code
- Local-only inference works: Gemma 4 31B Dense at your-llm-host:8090, zero cloud cost
Adler-32 used BASE=255 instead of 65521. RFC 1950 mandates 65521 (largest prime less than 2^16). The model invented constants. Spec extraction CORRECTLY identified this as RFC 1950 — Stage 4 ignored the spec.
- Found by: differential test producing different checksums
- Fix complexity: trivial (one regex)
- Severity: CRITICAL — would have shipped wrong cryptography
The compress() function returns Ok with a zero-filled output buffer. No DEFLATE algorithm exists. Source code literally contains comments like // Since we don't have the actual algorithm, we use a simple heuristic and // for this spec, we'll assume the compression is successful.
Found in:
zlib-compression/src/compress.rs— 11 instances of "we don't have", "simulate", "for this spec"zlib-compression/src/uncompr.rs— same patternzlib-io/src/deflate.rs— 3unimplemented!()calls
The model recognized it didn't know how to implement DEFLATE/inflate but wrote stubs that compile rather than failing loudly.
- Found by: compress→uncompress roundtrip failing at C-side decompress with Z_DATA_ERROR (-3)
- Fix complexity: HIGH — needs real algorithm implementation
- Severity: CRITICAL — entire purpose of the library doesn't work
No CRC-32 compute function exists in the generated Rust. The "crc32" module in zlib-io contains only table-writing helpers (write_crc32_table, byte_swap). The actual crc32(data: &[u8]) -> u32 doesn't exist anywhere.
Found via: searching for compute functions across all crates.
-
Architecture said zlib-io would have CRC-32
-
Spec extraction had
crc32_checksumalgorithm -
Implementation generated I/O helpers instead
-
Fix complexity: HIGH — needs to detect and re-prompt for missing functions
-
Severity: HIGH — algorithm declared by architecture but not implemented
The model conflated z_stream (the public stream type) and inflate_state (internal state). Methods declared on one were called on the other. Required ~50 reactive field additions across multiple iterations.
- Found by: cargo check errors during fix loop
- Fix complexity: MEDIUM — needs upfront type schema
- Severity: MEDIUM — cascaded into many compile errors
| Algorithm | Compiles | Mathematically Correct | Notes |
|---|---|---|---|
| Adler-32 | ✅ | ✅ (after BASE fix) | 30K random inputs match C zlib exactly |
| CRC-32 | ✅ (helpers only) | ❌ | Compute function never generated |
| compress() | ✅ | ❌ | Returns zeros |
| uncompress() | ✅ | ❌ | Cannot decompress real DEFLATE |
| deflate (lib) | ✅ | ❌ | 18 stubs/unimplemented |
| inflate (lib) | ✅ | ❓ Untested | Likely broken given pattern |
| trees | ✅ | ❓ Untested | |
| zlib-types | ✅ | N/A | Just type defs |
4/7 crates compile but are functionally broken. 1/7 crate (Adler-32) is correct after one constant fix. 3/7 crates (types, trees, basic structure) are at least structurally sound.
Currently: Stage 4 generates code → fix loop until it compiles. Required: Stage 4 generates code → runs spec test_vectors → fix loop until tests pass.
Implementation:
- Every AlgorithmSpec must include test_vectors (already in schema)
- Stage 4 generates the test FIRST:
assert_eq!(adler32(b"Wikipedia"), 0x11e60398) - Generates the implementation
- Compiles and runs tests
- If tests fail, iterates with
cargo testerrors as feedback (not justcargo check) - Refuses to mark crate "complete" until tests pass
This catches Bug Class 1 (wrong constants) at generation time. The Adler-32 BASE bug would have failed iteration 1 instead of needing manual diff testing.
Current scrubber catches typos. New scrubber must catch generation lies:
unimplemented!()in non-test code → REJECT GENERATIONtodo!()in production code → REJECT- Comments matching
we don't have | for this spec | conceptually | simulate→ REJECT - Functions that take input but never use it (just return Ok) → REJECT
- Output buffers that are never written → REJECT
When detected: re-prompt with explicit instruction "implement the actual algorithm, do not stub or simulate".
Each spec lists source_functions: [adler32, adler32_combine]. After Stage 4:
- Walk every source_function
- Verify a corresponding pub fn exists
- If not, RE-PROMPT for missing function with full spec context
This catches Bug Class 3 (CRC-32 missing).
Current Stage 5 is a stub. Must become:
- Auto-generate FFI bindings for every C public function
- Auto-generate proptest harness for each
- Run 10K+ random inputs through both implementations
- Report exact matches, ULP tolerance for floats, roundtrip equivalence for compression
- REFUSE to declare success without passing differential tests
Stage 2 currently allows specs without test_vectors. New requirement:
- Every AlgorithmSpec MUST have ≥1 test_vector
- For algorithms referencing standards (RFC, FIPS, NIST), MUST extract test vectors from the standard
- Re-prompt extraction if missing
Before generating bodies, generate just types + signatures + unimplemented!() bodies. Verify whole workspace compiles. Only then fill bodies. Catches type-system errors (Bug Class 4) before they cascade.
Already built in architect/field_scanner.py. Wire into pipeline so types are generated complete on first pass.
Have a second LLM call review each spec extraction:
- Are the constants plausible? (BASE=255 is wrong for Adler-32; reviewer would flag)
- Are the test vectors mathematically consistent?
- Cross-reference cited standards
Current fix loop sees cargo check errors. Enhanced version sees:
- The original spec
- Cited standards (link to RFC text)
- Test vectors from the standard
- Adjacent files in the crate
When fix attempt fails, retry with HEAVIER context (full spec + standard text), then escalate to a stronger model.
Wire the validator, field scanner, holistic fixer into alchemist translate. Currently they're standalone scripts. Should be: alchemist translate ./mbedtls/ and have it just work.
Run on:
- mbedTLS (crypto, NIST CAVP test vectors)
- lwIP (TCP/IP, can compare against smoltcp)
- FreeRTOS (RTOS kernel)
- SQLite (boss fight)
Each surfaces new failure classes. Each becomes a generic fix.
Domain-specific extension points:
- Crypto plugin (auto-imports test vectors, knows constant-time requirements)
- RTOS plugin (handles interrupt contexts, no_std requirements)
- Networking plugin (packet handling patterns)
| Phase | Work | Time | Reliability after |
|---|---|---|---|
| Phase 1 (done) | Validator, scrubber, holistic fix | ✅ Done | ~57% crates compile |
| Phase 2 | TDD Stage 4, anti-stub, API completeness | 6-10 weeks | ~70% crates compile + correct on simple algos |
| Phase 3 | Skeleton stage, spec validation, context fix | 4-6 weeks | ~85% on standard codebases |
| Phase 4 | Multi-codebase, plugins, productionize | 4-6 weeks | Reliable for common library types |
| Phase 5 | Hard targets (kernels, drivers, generics) | 12+ weeks | Honest 50-70% on arbitrary C |
Total: 6-9 months of focused work to reach "anyone with normal C code gets working Rust"
For exotic C (embedded with hand-written assembly, kernel drivers, OS code), expect to never hit 100%. Those need human input on architecture.
If you handed Alchemist (today) to a developer and asked "translate my C library":
| C codebase profile | Current likely outcome |
|---|---|
| Pure stateless algorithm (single function) | High chance of compiling AND being correct |
| Algorithm library with state (zlib pattern) | Will compile, ~30-50% of functions actually work |
| Crypto library with test vectors | Will compile, semantic correctness unknown |
| Networking stack | Will compile, packet handling broken |
| Embedded RTOS | Will compile, scheduling probably non-functional |
| Kernel module | May not compile, definitely incorrect |
Current Alchemist is a powerful research tool that proves the algorithm-first methodology works. It's not yet a tool you'd hand to a stranger and trust the output without verification.
The PATH to that trustworthy state is clear (Tier 1 work), but it's months of work, not days.
- Build TDD Stage 4 (Tier 1.1) — biggest leverage, prevents most bug classes
- Add anti-stub scrubber rules (Tier 1.2) — quick win, prevents silent failures
- Wire differential testing into pipeline (Tier 1.4) — automates what we did manually today
- Apply lessons to mbedTLS (Tier 3.11) — proves generalization
Each surfaces new requirements. Iterate.
The verification step did its job. Without it, we would have shipped:
- Cryptographically wrong checksums
- A "compress" function that returns zeros
- A "decompress" function that cannot decompress
- A workspace that compiles but is functionally non-operational
The methodology (algorithm-first, per-file gen, scrubber, holistic fix) is real. The remaining work to make Alchemist production-grade is engineering, not research.