Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
a2507d5
v2 python prototype.
BrianPugh Oct 15, 2025
33bc24a
update pi pico firmware download to datasets.
BrianPugh Jan 24, 2026
2c46184
remove wrap-around logic; adds additional complications for minimal g…
BrianPugh Jan 24, 2026
e503cdd
Prepare cython bindings for v2 flag.
BrianPugh Jan 24, 2026
8dba220
add mssing extended-match-count flush.
BrianPugh Jan 24, 2026
bd7762d
common.h: add TampConf.v2 attribute and associated macros
BrianPugh Jan 24, 2026
0b208ff
wip c decompressor
BrianPugh Jan 24, 2026
5dbcefb
swap window/extended-match length in encoding
BrianPugh Jan 24, 2026
b377d18
more cleanup
BrianPugh Jan 24, 2026
667e3cf
remove rle_last_written check; provides very small benefits, but unne…
BrianPugh Jan 24, 2026
aea413d
rename pending_symbol to token_state.
BrianPugh Jan 25, 2026
1846270
Make decompression 1% slower to save 200 bytes in firmware
BrianPugh Jan 25, 2026
ce3bd94
narrow variable scope
BrianPugh Jan 25, 2026
34ad99c
remove extended-match wrapping logic.
BrianPugh Jan 25, 2026
4cdb50f
move TAMP_OUTPUT_FULL logic to top of loop
BrianPugh Jan 25, 2026
70fd739
further reduce binary size by 56 bytes via a goto.
BrianPugh Jan 25, 2026
6b59265
use some math instead of if/else
BrianPugh Jan 25, 2026
59e4090
no need for v2_res
BrianPugh Jan 25, 2026
f59fd08
simplify while-loop check with a union. reduces binary by 56 bytes
BrianPugh Jan 25, 2026
a925f62
unified huffman decode.
BrianPugh Jan 25, 2026
e69b826
Add comment about HUFFMAN_TABLE being pretty optimized.
BrianPugh Jan 25, 2026
589a9a2
Make some datatypes smaller; reduces binary by 36 bytes.
BrianPugh Jan 25, 2026
e081f53
reduce some dtypes to uint8
BrianPugh Jan 25, 2026
66bdc09
prep cython bindings for c-compressor-v2
BrianPugh Jan 25, 2026
bfe9631
don't wrap extended match
BrianPugh Jan 26, 2026
37c3608
more robust window_copy
BrianPugh Jan 26, 2026
19baefb
simplify rle criteria
BrianPugh Feb 1, 2026
5ae0282
simplify window_copy call
BrianPugh Feb 1, 2026
983532c
move window_copy to a better location.
BrianPugh Feb 1, 2026
131c25a
more comments
BrianPugh Feb 1, 2026
57aeacb
cleanup decompressor v2 flag check.
BrianPugh Feb 1, 2026
edb6ed4
decompressor fix.
BrianPugh Feb 1, 2026
d2a6f3c
fix infinite loop
BrianPugh Feb 2, 2026
f55772b
configure pytest in pyproject.toml
BrianPugh Feb 2, 2026
9d1b785
initial v2 c compressor implementation; needs optimizing.
BrianPugh Feb 2, 2026
775ee58
v2-compressed datasets
BrianPugh Feb 2, 2026
b573f3a
simplify pattern-extending.
BrianPugh Feb 2, 2026
391efdc
dead code cleanup
BrianPugh Feb 2, 2026
7366085
more simplification
BrianPugh Feb 2, 2026
8c222e3
make window_pos a uint16 instead of a bitfield.
BrianPugh Feb 2, 2026
c8c39c2
decompress on-device-compression-benchmark results to check validity.
BrianPugh Feb 2, 2026
0cba4ea
more firmware optimizations
BrianPugh Feb 2, 2026
1d06495
rework compressor struct.
BrianPugh Feb 2, 2026
e51f184
update mpy_bindings with v2 flag.
BrianPugh Feb 2, 2026
961803a
prevent TAMP_COMPRESS_FULL for extended-match
BrianPugh Feb 2, 2026
3f46663
don't inline rle/extended-match
BrianPugh Feb 2, 2026
02c596e
Add .clangd to the gitignore
BrianPugh Feb 3, 2026
fe16ce9
Add v2 option to wasm
BrianPugh Feb 3, 2026
41b4b13
Add v2 to the website.
BrianPugh Feb 3, 2026
865d051
rename v2 field to 'extended'
BrianPugh Feb 3, 2026
a0a7543
Change cppcheck to use local
BrianPugh Feb 3, 2026
0652b98
Add singular TAMP_EXTENDED flag; better document the compile-time flags.
BrianPugh Feb 3, 2026
f1a06db
Mention extended field in javascript docs.
BrianPugh Feb 3, 2026
8fb8042
update README, add ablation study.
BrianPugh Feb 3, 2026
23239dd
Address copilot feedback
BrianPugh Feb 3, 2026
2d1829a
update specs for v2
BrianPugh Feb 4, 2026
eb072c9
document RLE edgecase
BrianPugh Feb 4, 2026
050c2d0
fix(wasm): add cancel handlers to streams to prevent memory leaks
BrianPugh Feb 4, 2026
eebc663
update README
BrianPugh Feb 4, 2026
f614a00
combine some TAMP_LAZY_MATCHING blocks
BrianPugh Feb 4, 2026
a898779
more macro conditional blocks combined
BrianPugh Feb 4, 2026
34f48be
combine some write_to_bit_buffer calls, reducing binary by 20~36 bytes
BrianPugh Feb 4, 2026
d8828bc
replace hard-coded values with their math formulas
BrianPugh Feb 4, 2026
578fcea
build header from conf rather than compressor values. Slightly more e…
BrianPugh Feb 4, 2026
b6cdf4f
shrink binary more by embedding conf into TampCompressor instead of r…
BrianPugh Feb 4, 2026
bbbdfe4
Remove micropython viper references from the README
BrianPugh Feb 4, 2026
484131a
don't include the stream API in micropython native module.
BrianPugh Feb 4, 2026
6d3d26f
Add likely/unlikely hints to micropython bindings
BrianPugh Feb 4, 2026
a5d7691
don't inline write_to_bitbuffer to save around 60 bytes.
BrianPugh Feb 4, 2026
d6325dd
cache LFS files.
BrianPugh Feb 4, 2026
4718421
immediately update lfs cache
BrianPugh Feb 4, 2026
ae9e8ff
stop testing the viper implementation.
BrianPugh Feb 4, 2026
4392f2b
skip the dataset tests when building wheels
BrianPugh Feb 4, 2026
5280770
update expected enwik8 hash
BrianPugh Feb 4, 2026
f8ad5d3
Fix window corruption.
BrianPugh Feb 5, 2026
ad98ad3
share window_copy between compressor/decompressor.
BrianPugh Feb 5, 2026
4bd7b10
cache-on-the-stack unpacked bitfields.
BrianPugh Feb 5, 2026
c582fb7
thorough extended-match search.
BrianPugh Feb 5, 2026
f016879
better RLE vs match tradeoff in C compressor
BrianPugh Feb 5, 2026
57f0c48
match python compressor to C compressor implementation.
BrianPugh Feb 5, 2026
161e476
update readme and expected hash
BrianPugh Feb 5, 2026
c6f23f4
don't inline find_best_match
BrianPugh Feb 5, 2026
aa59de5
fix initialization warning
BrianPugh Feb 5, 2026
538b8c0
combine if-statement; saving 8 bytes.
BrianPugh Feb 5, 2026
66401ac
save 48 bytes in tamp_compressor_flush using some gotos
BrianPugh Feb 5, 2026
8e710df
save 12 more bytes
BrianPugh Feb 5, 2026
e55710d
save 44 more bytes
BrianPugh Feb 5, 2026
65f9812
cleanup flush_done
BrianPugh Feb 5, 2026
9aefc6e
update expected javascript hash
BrianPugh Feb 5, 2026
f47b547
consolidate extended compression functions
BrianPugh Feb 5, 2026
ea38c62
simplify find_extended_match, deduplicate checks from caller
BrianPugh Feb 5, 2026
178bf19
don't need to reset extended_match_position.
BrianPugh Feb 5, 2026
330e5f4
combine if-statements
BrianPugh Feb 5, 2026
83d3d8e
consolidate write_extneded_match_token output size checks.
BrianPugh Feb 5, 2026
d0c2b36
consolidate output arithmatic to partial_flush.
BrianPugh Feb 5, 2026
7abf720
consolidate output arithmatic to write_extended_match_token.
BrianPugh Feb 5, 2026
750b002
update docstrings
BrianPugh Feb 5, 2026
f68aa6f
get rid of useless brackets
BrianPugh Feb 5, 2026
f8b1bfc
update CLAUDE.md
BrianPugh Feb 6, 2026
238ec2d
note: always inline refill_bit_buffer.
BrianPugh Feb 6, 2026
1ab913e
further flushing optimization.
BrianPugh Feb 6, 2026
627cb38
TAMP_OPTIMIZE_SIZE macro
BrianPugh Feb 6, 2026
95c770a
extract out extended bits to its own private polling function.
BrianPugh Feb 6, 2026
b31ce73
more TAMP_OPTIMIZE_SIZE attributes
BrianPugh Feb 6, 2026
cde27cf
some more gcc pragmas to shrink implementation
BrianPugh Feb 6, 2026
1d82747
update readme binary-size table
BrianPugh Feb 6, 2026
c52f165
avoid memset
BrianPugh Feb 6, 2026
bf1c377
TAMP_USE_MEMSET macro
BrianPugh Feb 9, 2026
9a66abf
xtensa-specific nonsense
BrianPugh Feb 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
datasets/v1-compressed/** filter=lfs diff=lfs merge=lfs -text
datasets/extended-compressed/** filter=lfs diff=lfs merge=lfs -text
14 changes: 7 additions & 7 deletions .github/workflows/build_wheels.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ jobs:
CIBW_ARCHS: ${{ matrix.cibw_archs }}
CIBW_BUILD: ${{ matrix.cibw_build }}
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests
CIBW_TEST_COMMAND: pytest {package}/tests --no-dataset

- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -164,7 +164,7 @@ jobs:
CIBW_ARCHS: ${{ matrix.cibw_archs }}
CIBW_BUILD: ${{ matrix.cibw_build }}
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests
CIBW_TEST_COMMAND: pytest {package}/tests --no-dataset

- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -212,7 +212,7 @@ jobs:
CIBW_ARCHS: ${{ matrix.cibw_archs }}
CIBW_BUILD: ${{ matrix.cibw_build }}
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests
CIBW_TEST_COMMAND: pytest {package}/tests --no-dataset

- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -254,7 +254,7 @@ jobs:
CIBW_ARCHS: ${{ matrix.cibw_archs }}
CIBW_BUILD: ${{ matrix.cibw_build }}
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests
CIBW_TEST_COMMAND: pytest {package}/tests --no-dataset

- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -302,7 +302,7 @@ jobs:
CIBW_ARCHS: ${{ matrix.cibw_archs }}
CIBW_BUILD: ${{ matrix.cibw_build }}
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests
CIBW_TEST_COMMAND: pytest {package}/tests --no-dataset

- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -344,7 +344,7 @@ jobs:
CIBW_ARCHS: ${{ matrix.cibw_archs }}
CIBW_BUILD: ${{ matrix.cibw_build }}
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests
CIBW_TEST_COMMAND: pytest {package}/tests --no-dataset

- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -385,7 +385,7 @@ jobs:
CIBW_ARCHS: ${{ matrix.cibw_archs }}
CIBW_BUILD: ${{ matrix.cibw_build }}
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests
CIBW_TEST_COMMAND: pytest {package}/tests --no-dataset

- uses: actions/upload-artifact@v4
with:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/javascript.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ jobs:
cd build
HASH=$(sha256sum enwik8-js.tamp | cut -d' ' -f1)
echo "Compression hash: $HASH"
if [ "$HASH" != "02e05af059a0040d641988075cf1dfc479a084f9a34b5c8a348354211c5fa038" ]; then
if [ "$HASH" != "dd5e431b0cbaa6ee001b10493c2b08e6235f42e3f4ce00958e88b1b97581872e" ]; then
echo "❌ Hash mismatch!"
echo "Expected: 02e05af059a0040d641988075cf1dfc479a084f9a34b5c8a348354211c5fa038"
echo "Expected: dd5e431b0cbaa6ee001b10493c2b08e6235f42e3f4ce00958e88b1b97581872e"
echo "Got: $HASH"
exit 1
fi
Expand Down
54 changes: 52 additions & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,48 @@ jobs:
source .venv/bin/activate
SKIP=wasm-eslint,wasm-npm-test,wasm-file-validation,typescript-check,package-json-lint pre-commit run --show-diff-on-failure --color=always --all-files

cache-lfs:
name: 'Cache LFS files'
runs-on: ubuntu-latest
outputs:
cache-key: ${{ steps.lfs-key.outputs.key }}
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
submodules: recursive
lfs: false

- name: Compute LFS cache key
id: lfs-key
run: |
# Hash pointer files before they get replaced by git lfs pull
# Use find for reliable recursive globbing, sort for deterministic order
hash=$(find datasets/v1-compressed datasets/extended-compressed -name '*.tamp' -type f | sort | xargs cat | sha256sum | cut -d' ' -f1)
echo "key=lfs-${hash}" >> $GITHUB_OUTPUT
echo "Cache key: lfs-${hash}"

- name: Restore LFS cache
uses: actions/cache/restore@v4
id: lfs-cache
with:
path: .git/lfs
key: ${{ steps.lfs-key.outputs.key }}

- name: Pull LFS files
if: steps.lfs-cache.outputs.cache-hit != 'true'
run: git lfs pull

- name: Save LFS cache
if: steps.lfs-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: .git/lfs
key: ${{ steps.lfs-key.outputs.key }}

test:
name: 'Test Python ${{ matrix.python-version }}'
needs: cache-lfs
timeout-minutes: 15
runs-on: ubuntu-latest
strategy:
Expand All @@ -110,7 +150,17 @@ jobs:
uses: actions/checkout@v4
with:
submodules: recursive
lfs: true
lfs: false

- name: Restore LFS cache
uses: actions/cache/restore@v4
with:
path: .git/lfs
key: ${{ needs.cache-lfs.outputs.cache-key }}
fail-on-cache-miss: true

- name: Pull LFS files
run: git lfs pull

- name: Set up python 3.13 (for Poetry)
id: setup-python-system
Expand Down Expand Up @@ -217,7 +267,7 @@ jobs:
implementation: [desktop, embedded]
env:
POETRY_HOME: '~/poetry'
EXPECTED_COMPRESSED_HASH: '02e05af059a0040d641988075cf1dfc479a084f9a34b5c8a348354211c5fa038'
EXPECTED_COMPRESSED_HASH: 'dd5e431b0cbaa6ee001b10493c2b08e6235f42e3f4ce00958e88b1b97581872e'

steps:
- name: Check out repository
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,12 @@ Temporary Items
# Compression benchmark datasets
datasets/*
!datasets/v1-compressed/
!datasets/extended-compressed/
enwik8*
*.pkl
*.tamp
!datasets/v1-compressed/**
!datasets/extended-compressed/**

# Cython-generated files
tamp/_c_compressor.c
Expand Down Expand Up @@ -435,6 +437,9 @@ wasm/build/
*.swo
*~

# clangd (C/C++ language server)
.clangd

# Emacs
*~
\#*\#
Expand Down
7 changes: 5 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,13 @@ repos:
args: ['-style=file', '-i']
exclude: ^espidf/tamp/private/tamp_search\.hpp$

- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.3.5
- repo: local
hooks:
- id: cppcheck
name: cppcheck
entry: cppcheck
language: system
files: \.(c|h|cpp|hpp)$
exclude: ^(espidf|mpy_bindings|ctests|tools)/
args: [
'-Itamp/_c_src',
Expand Down
111 changes: 93 additions & 18 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ different platforms:
**Shared C Source:** All implementations use the same C source code in
`tamp/_c_src/tamp/`:

- `common.h/c` - Shared utilities and data structures
- `compressor.h/c` - Compression implementation
- `common.h/c` - Shared utilities, data structures, stream I/O callbacks, and
dictionary initialization
- `compressor.h/c` - Compression implementation (sink/poll low-level API and
higher-level compress/flush API)
- `decompressor.h/c` - Decompression implementation
- `compressor_find_match_desktop.c` - Desktop-optimized match finding (included
by `compressor.c` on non-embedded targets)

## Development Commands

Expand Down Expand Up @@ -162,38 +166,81 @@ make website-clean # Clean website build artifacts
**WebAssembly Build Process:**

1. `wasm/Makefile` compiles C source to WebAssembly using Emscripten
2. `wasm/scripts/build.js` generates multiple JS/TS distribution formats
2. `tsup` (via `npm run build:js`) bundles into multiple JS/TS distribution
formats (CJS, ESM, `.d.ts`)
3. Exports specific C functions and runtime methods for JS interop

**Configuration Flags:**
**Configuration Flags (compile-time `-D` defines):**

- `TAMP_LAZY_MATCHING=1` - Enable lazy matching optimization (default)
- `TAMP_ESP32=1` - ESP32-specific optimizations
- `TAMP_LAZY_MATCHING=1` - Enable lazy matching optimization (default in
build.py)
- `TAMP_ESP32=1` - ESP32-specific optimizations (avoids bitfields for speed)
- `TAMP_COMPRESSOR`/`TAMP_DECOMPRESSOR` - Include/exclude components
- `TAMP_EXTENDED=1` - Master switch for extended format: RLE and extended match
(default: 1). `TAMP_EXTENDED_COMPRESS` and `TAMP_EXTENDED_DECOMPRESS` can
individually override.
- `TAMP_STREAM=1` - Include stream API (default: 1). Disable with
`-DTAMP_STREAM=0` to save ~2.8KB.
- `TAMP_STREAM_WORK_BUFFER_SIZE=32` - Stack-allocated work buffer for stream API
(default: 32 bytes, 256+ recommended for performance)
- `TAMP_STREAM_MEMORY` / `TAMP_STREAM_STDIO` / `TAMP_STREAM_LITTLEFS` /
`TAMP_STREAM_FATFS` - Enable built-in I/O handlers for specific backends
- `TAMP_USE_EMBEDDED_MATCH=1` - Force embedded `find_best_match` implementation
on desktop (for testing)

**Build Environment Variables (Python):**

- `TAMP_SANITIZE=1` - Enable AddressSanitizer + UBSan
- `TAMP_PROFILE=1` - Enable profiling (line trace, debug info)
- `TAMP_USE_EMBEDDED_MATCH=1` - Force embedded match finding
- `TAMP_BUILD_C_EXTENSIONS=0` - Skip building C extensions entirely
- `CIBUILDWHEEL=1` - CI wheel building mode (disables allowed_to_fail)

### Testing Strategy

**Multi-layered Testing:**

- **Python tests** (`tests/`) - Core algorithm testing using pytest
- **Python tests** (`tests/`) - Core algorithm testing using pytest. Includes
bit reader/writer, compressor, decompressor, round-trip, CLI, dataset
regression, and file interface tests.
- **WebAssembly tests** (`wasm/test/`) - JS/TS API testing with Node.js test
runner
runner (`node --test`)
- **C tests** (`ctests/`) - Low-level C API testing using Unity framework
(submodule at `ctests/Unity/`). Includes stream API tests and filesystem
integration tests with LittleFS and FatFS RAM backends.
- **Integration tests** - Cross-platform compatibility and performance
benchmarks

**Test Data Sources:**

- Enwik8 dataset (100MB) for performance benchmarking
- Silesia corpus for compression ratio evaluation
- Enwik8 dataset (100MB) for performance benchmarking (`make download-enwik8`)
- Silesia corpus for compression ratio evaluation (`make download-silesia`)
- Custom test cases for edge conditions

### Compressor Architecture

The C compressor uses a two-phase low-level API:

1. `tamp_compressor_sink()` - Copies input bytes into a 16-byte internal ring
buffer (cheap/fast)
2. `tamp_compressor_poll()` - Runs one compression iteration on the internal
buffer (computationally intensive)

Higher-level convenience functions (`tamp_compressor_compress`,
`tamp_compressor_compress_and_flush`) wrap these. Callback variants (`_cb`
suffix) accept a `tamp_callback_t` progress callback.

The stream API (`tamp_compress_stream`, `tamp_decompress_stream`) provides a
file-oriented interface using read/write callbacks, supporting multiple I/O
backends (memory, stdio, LittleFS, FatFS).

### Memory Management Patterns

**Key Principle:** Fixed memory usage during compression/decompression

- Window size determines memory usage: `(1 << windowBits)` bytes
- No dynamic allocation during compression/decompression operations
- Stream API uses a stack-allocated work buffer (`TAMP_STREAM_WORK_BUFFER_SIZE`)
- Streaming interfaces require explicit resource management (`destroy()` calls
in JS/TS)

Expand All @@ -202,7 +249,9 @@ make website-clean # Clean website build artifacts
### Making Changes to Core Algorithm

1. **Modify C source** in `tamp/_c_src/tamp/`
2. **Rebuild all implementations:**
2. **Update pure Python reference** in `tamp/compressor.py` /
`tamp/decompressor.py` to match
3. **Rebuild all implementations:**

```bash
# Python
Expand All @@ -212,11 +261,12 @@ make website-clean # Clean website build artifacts
cd wasm && npm run build
```

3. **Run comprehensive tests:**
4. **Run comprehensive tests:**
```bash
make test # Python + MicroPython
poetry run pytest # Python tests
make c-test # C unit tests with sanitizers
make c-test-embedded # C tests with embedded match finding
cd wasm && npm test # WebAssembly
make c-test # C unit tests
```

### Adding New Features
Expand All @@ -232,11 +282,13 @@ make website-clean # Clean website build artifacts
- **Use provided benchmarking tools:**
```bash
make on-device-compression-benchmark # MicroPython performance
npm run test:enwik8 # WebAssembly performance
python tools/performance-benchmark.sh # Python performance
cd wasm && npm run test:enwik8 # WebAssembly performance
bash tools/performance-benchmark.sh # Python performance
make c-benchmark-stream # C stream API benchmark
make binary-size # ARM binary size table
```
- **Profile with:** `tools/profiler.py` for Python, browser dev tools for
WebAssembly
- **Profile with:** `tools/profiler.py` for Python (requires `TAMP_PROFILE=1`),
browser dev tools for WebAssembly

### Release Process

Expand All @@ -247,6 +299,29 @@ make website-clean # Clean website build artifacts
- WebAssembly npm package
3. **CI/CD handles** cross-platform builds and testing

### Python Import Fallback Chain

`tamp/__init__.py` imports Compressor/Decompressor using this priority:

1. Viper (MicroPython optimized) - only available on MicroPython
2. Cython C extensions (`_c_compressor`/`_c_decompressor`) - primary on CPython
3. Pure Python reference (`compressor.py`/`decompressor.py`) - fallback

When modifying compression behavior, changes to the C source must be mirrored in
the pure Python reference implementation to keep them in sync.

### CI/CD

GitHub Actions workflows (`.github/workflows/`):

- `tests.yaml` - Lint (ruff, pre-commit) and test across Python 3.9/3.12/3.13
and multiple OS. Also runs `c-test` and `c-test-embedded`.
- `build_wheels.yaml` - Cross-platform wheel builds via cibuildwheel
- `javascript.yaml` - WebAssembly tests on Node 18/20
- `mpy_native_module.yaml` - MicroPython native module builds for ARM
architectures
- `esp_upload_component.yml` - ESP-IDF component registry upload

## Documentation Style

- Avoid "fake" subsections (e.g., bold text like `**Error Promotion:**` acting
Expand Down
Loading
Loading