litelite 0.2.0

A kit for purpose-sized languages: buy total verification with smallness. Diagnostics, lexing, parsing, fuel, and capability tables — the invariants paid once.
Documentation
# CLAUDE.md — litelite

Read this first. It is the whole operating map; `GENESIS.md` is the origin
story + full roadmap; `paper/OUTLINE.md` is the research plan. This repo is
SELF-CONTAINED — never read the parent `localharness` repo into context; its
knowledge was distilled here at genesis.

## What this is

A kit for **purpose-sized languages**. Thesis: smallness is not a cost — it
BUYS guarantees big languages can't give. Fuel-bounded evaluation = a
termination proof. A host-capability table = a complete effect bound. The
product is **guarantees, not languages**: pick the guarantees (halts within N
fuel, touches only these capabilities, output ≤ Y bytes), get the largest
language for which they stay mechanical.

Parents: rustlite, soliditylite, bashlite (~19K LOC in `localharness`), each
hand-rolled these kernel pieces with divergent bugs (a missing depth guard,
the twice-fixed mojibake bug, three unrelated fuels — GENESIS has the full
story). This kit pays each invariant once.

## THE CONSTITUTION (hard rules — CI-enforced where possible)

1. **Zero external dependencies** in every kit crate. `std` only. If a feature
   needs a dep, the feature is out of scope. (Languages BUILT on the kit may
   have deps; the kit may not.)
2. **Caps** (`scripts/caps.sh`, run by CI): ≤2,000 LOC per crate, ≤25,000 LOC
   repo total, CLAUDE.md ≤8,000 chars. At a cap: split, shrink, or kill —
   never raise the cap. The parents both died at ~120K LOC; the cap is why
   this repo can't.
3. **No milestone without a named consumer.** Nothing lands "because it's
   cleaner." Every change names who needs it (a language in this repo, a
   paper experiment, or an external consumer like localharness/bashlite).
   This repo is a compiler-nerd attractor; the consumer rule is the leash.
4. **Never a unified codegen trait.** wasm (structured/relative control flow),
   EVM (absolute jumps/labels), and tree-walk evaluation are semantically
   irreconcilable — proven in the parents. Emitters ship as independent
   libraries, period.
5. **wasm32 always green**: `cargo check --target wasm32-unknown-unknown`
   passes at every commit. No cfg-gated escape hatches in kit crates.
6. **Narrative lives in GENESIS.md and the paper, never in code.** Crate and
   symbol names stay boring and literal.
7. **Naming: NO dashes, lite goes LAST.** Crates are single dashless words
   with the `lite` suffix (`diaglite`, `lexlite`, `parselite`, `fuellite`;
   languages too: `bashlite`, `prooflite`, `stratlite`). The facade alone is
   `litelite` — the kit of lites. Never write the dashed form anywhere
   (caps.sh greps for it).
8. **Don't silently miscompile/misparse** — every failure is a coded, spanned
   `Diag`. A wrong-but-clean result is worse than an error.
9. Commit AND push promptly; unpushed work is invisible.

## Map

```
Cargo.toml            workspace + the `litelite` facade crate (src/lib.rs re-exports)
crates/
├── diaglite/   Span, Diag (message+span+u16 code), line_col, render_snippet
│               (caret snippets; floor_char_boundary guards mid-char offsets)
├── lexlite/    Cursor byte-lexer kit: eat/eat_while/spans, line+block comments
│               (nested flag EXPLICIT), eat_ident/eat_decimal/eat_hex,
│               next_char (UTF-8-safe — never byte-cast)
├── parselite/  TokCursor<T: Tok> recursive-descent harness: clamping advance
│               (EOF-sentinel convention), eat(pred), enter/leave depth guard
│               (DEFAULT_MAX_DEPTH=96), guarded() pairs enter/leave always
├── fuellite/   Fuel (burn/Exhausted — pass ONE &mut Fuel into every
│               sub-evaluation; never fork a child budget) + ByteBudget
│               (grant/push_str clip-at-char-boundary/push_bytes)
├── caplite/    M2: Cap/CapTable as DATA. trait Ty (syms are ABI), check_args,
│               validate/validate_flat (ident-only strings — EVERY interpolated
│               string is an injection channel), docs_markdown, versioned
│               parity manifest + FNV-1a-64 hash for the far side of a boundary
├── evmlite/    M3 emitter: asm (op SSOT, min-width push, two-pass PUSH2 label
│               back-patch, init_wrapper; sticky AsmError — never panic or
│               truncate) + interp diff-oracle (step/mem/stack caps, real
│               JUMPDEST analysis, revert rollback, keccak=Unsupported)
├── modlite/    M3 emitter: wasm module builder (wasmlite taken) — LEB128,
│               functype interning, locals RLE, section framing; sticky
│               BuildError (import-after-func shift, spec-invalid limits)
├── prooflite/  M1+M2 reference language (not in the facade): total, fueled;
│               i64+bool, let/assign/print/if/repeat, checked arithmetic,
│               caplite host calls (table SNAPSHOTTED once/run); codes E00xx/
│               E01xx/E02xx. NB: binary folds charge the depth guard — it
│               bounds parser recursion, NOT AST depth
├── stratlite/  M4 language: total, fuel-bounded strategies. lookback pragma,
│               var slots (bar-ATOMIC: faulted bars roll back), per-bar body →
│               signal; fresh fuel/bar; static indicator windows; no look-ahead
│               BY CONSTRUCTION (prefix-invariance tested); REFERENCE card
├── backtestlite/ M4 verifier: deterministic integer engine (fills at next
│               open, adverse validated Costs), Report: Eq + equity_hash
│               (FNV over the final curve), Gate, verify() →
│               Reject{Compile,Run,Gate} — paper §5's predicate. Codes E03xx
├── applite/    M7 language: total UI apps. state (literal-typed int/bool/str),
│               widgets (label/button/input/row/col/if), fuel-bounded ATOMIC
│               handlers (faults roll back), strings bounded per value + app,
│               static checker; REFERENCE = the prompt card. 1,999/2,000 LOC
app/                  M7 shell: the vibe-coding page — applite as wasm via a
                      hand-rolled C ABI (no deps, no bindgen), one index.html.
                      OUTSIDE the workspace (leaf artifact); ./app/build.sh
scripts/caps.sh       the constitution's teeth (LOC + CLAUDE.md caps)
scripts/publish.sh    dry run by default, --execute uploads; resumable
CHANGELOG.md          ONE version across every crate; a tag's notes come from here
paper/OUTLINE.md      the paper IS the product; experiments land as sections
GENESIS.md            origin, distilled parent learnings, roadmap M0–M5
experiment/           §5's RUN: model+candles+harness (deps OK: OUTSIDE the
                      workspace — rules 1+5 keep them out of the kit)

```

## Build / test / release

```sh
cargo test                                          # workspace + facade
cargo check --target wasm32-unknown-unknown         # must stay green
cargo fmt --check && cargo clippy -- -D warnings
bash scripts/caps.sh                                # the caps
bash scripts/publish.sh                             # rehearse a release
```

Version lives ONCE in `[workspace.package]` (cargo rejects drift against
`[workspace.dependencies]`). Tag `vX.Y.Z` → `release.yml`: every gate,
tag==version, CHANGELOG has that section, publish, GitHub release. Needs
`CARGO_REGISTRY_TOKEN`.

## Roadmap (each milestone's consumer + lesson: GENESIS.md)

- **M0–M4 (done, crates.io 0.1.0):** the Map IS the result. **§5 (done):**
  the paper's experiments ran, §5.2–5.8. **M7 (done):** applite + app/.
- **M5 (open):** re-home bashlite onto the kit inside localharness — the
  honest test of whether the kit carries its weight.

## Context / lineage (GENESIS.md has the full story)

localharness (github.com/compusophy/localharness): browser agents on Tempo;
its predecessor tempo-x402's result — verified self-play lifted a 0.5B model
1.5%→16.4% pass@1 — is this repo's empirical seed.