Skip to content

Commit bcc2049

Browse files
committed
feat(examples): worked examples, browser playground, Pages workflow, demo script
1 parent 7c187e7 commit bcc2049

7 files changed

Lines changed: 851 additions & 3 deletions

File tree

‎.github/workflows/pages.yml‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,34 @@ jobs:
3737

3838
- name: Build the wheel into docs/
3939
run: |
40+
set -euo pipefail
4041
python -m pip install --upgrade pip build
4142
python -m build --wheel --outdir docs/
42-
ls -la docs/
43+
test -f docs/index.html
44+
ls -1 docs/
4345
4446
- name: Point the page at the wheel it just built
4547
run: |
48+
set -euo pipefail
4649
wheel=$(basename docs/*.whl)
4750
echo "Built $wheel"
51+
52+
# The page pins a wheel filename, which carries the version. Rewrite
53+
# it so a version bump can never leave the demo fetching a 404.
4854
sed -i "s|\./fusejs_python-[^\"]*\.whl|./$wheel|" docs/index.html
49-
grep -o 'micropip.install("[^"]*")' docs/index.html
55+
56+
# Assert the rewrite landed, rather than trusting sed's exit code —
57+
# sed reports success when it matches nothing.
58+
if ! grep -qF "\"./$wheel\"" docs/index.html; then
59+
echo "::error file=docs/index.html::page does not reference ./$wheel"
60+
grep -o '\./fusejs_python[^"]*\.whl' docs/index.html || echo "(no wheel reference at all)"
61+
exit 1
62+
fi
63+
echo "docs/index.html references ./$wheel"
5064
5165
- name: Smoke-test the port before publishing it
5266
run: |
67+
set -euo pipefail
5368
python -m pip install docs/*.whl
5469
python - <<'PY'
5570
from fusejs import Fuse

‎PRESENTATION.md‎

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# 5-minute presentation / demo video
2+
3+
Working script for the Port Mortem 2026 submission. Everything below is a
4+
command that runs today — nothing here needs to be faked or edited in post.
5+
6+
**Rule for the whole video: never show a claim you don't immediately prove.**
7+
Judges have seen a hundred demos assert "100% compatible". Show the test runner.
8+
9+
---
10+
11+
## Before you record
12+
13+
```bash
14+
just build # deps installed, package importable
15+
npm install # once, for the compat run
16+
just check && just test # confirm green so nothing surprises you live
17+
python -m http.server 8000 --directory docs # if demoing the playground locally
18+
```
19+
20+
- Terminal at ~16pt, dark theme, window wide enough that `just compat`
21+
output doesn't wrap.
22+
- Have these tabs open: the GitHub repo, the live playground, `DECISIONS.md`.
23+
- Do one dry run. The fuzz and compat runs take real time — know exactly how
24+
long you're sitting there so you can talk over it.
25+
26+
---
27+
28+
## The script (5:00)
29+
30+
### 0:00–0:35 — The gap, not the library
31+
32+
> "Python has excellent fuzzy string matching. `rapidfuzz` will tell you how
33+
> close two strings are. What Python has *nothing* for is fuzzy **search** —
34+
> give me a collection of records, weighted fields, nested paths, query
35+
> operators, and rank them by relevance.
36+
>
37+
> That's what fuse.js is, and it only exists in JavaScript. So the capability
38+
> isn't missing from computing — it's trapped in the wrong ecosystem. I moved
39+
> it."
40+
41+
Don't say "I ported a library." Say what was missing and for whom.
42+
43+
### 0:35–1:20 — It solves a real problem
44+
45+
```bash
46+
python examples/ticket_triage.py
47+
```
48+
49+
> "Ten thousand support tickets a month, written by humans. Misspelled service
50+
> names, half a stack trace pasted in. This routes them against a runbook
51+
> catalogue — five auto-routed, one suggested, two escalated.
52+
>
53+
> The two escalated ones are about a coffee machine and a VPN request. That
54+
> matters: a fuzzy matcher *always* returns its best guess, so the score
55+
> cutoff, not the search, is what stops a confident wrong answer."
56+
57+
If you have time for a second, `reconcile.py` is the stronger data-engineering
58+
story (`ACME CORPORATION LTD` vs `Acme Corp. Limited`). Pick one, not both.
59+
60+
### 1:20–2:30 — The proof: the *original* suite runs against Python
61+
62+
This is the most important 70 seconds in the video. Slow down.
63+
64+
```bash
65+
just compat
66+
```
67+
68+
> "This is the fuse.js test suite. JavaScript, run by vitest, byte-for-byte
69+
> unmodified — I never touched a test file. A vitest alias redirects the one
70+
> import every spec shares to a shim that forwards every call into Python.
71+
>
72+
> 285 of 297 pass."
73+
74+
Then pre-empt the obvious question:
75+
76+
> "Twelve fail. Ten of them hand fuse.js a JavaScript *function* — a `sortFn`,
77+
> a `getFn` — and a closure over a live JS heap cannot be serialised into
78+
> Python at any price. The other two are divergences I chose on purpose and
79+
> documented. None of the twelve is a bug in the port."
80+
81+
### 2:30–3:20 — Behavioural equivalence, and the honest limit
82+
83+
```bash
84+
just fuzz 60
85+
```
86+
87+
Talk while it runs:
88+
89+
> "This generates random datasets, queries and options, runs them through both
90+
> engines, and compares. Fifty-one thousand cases, **zero structural
91+
> divergences** — same results, same order, same match indices.
92+
>
93+
> Scores agree to about 1e-13, not bit-for-bit. That's not a shortcut, it's a
94+
> wall: CPython's `pow` is correctly rounded and V8's isn't, and they disagree
95+
> by one unit in the last place on about 10% of calls.
96+
>
97+
> And that has one visible consequence. One ULP is enough to break a score
98+
> tie, so occasionally the two engines return the same documents in a
99+
> different order — eight times in fifty-one thousand. I claimed early on that
100+
> ordering was never affected. The fuzz run proved me wrong, so I corrected
101+
> it. That's in DECISIONS.md."
102+
103+
**Owning a corrected mistake on camera is worth more than a clean claim.**
104+
105+
### 3:20–4:10 — Play with it live
106+
107+
Open the playground (or `just demo --interactive`).
108+
109+
> "The port is pure Python with zero dependencies, which means it runs
110+
> unmodified in the browser under Pyodide. This page installs the actual wheel
111+
> — the same one you'd `pip install`."
112+
113+
Type `ste ham` → point at **Ste**ve / **Ham**ilton highlighting.
114+
Drag threshold to 0 → results vanish. Tick `use_extended_search`, type `^the`.
115+
116+
> "Same dataset as the official fuse.js demo — their own `books.json` — so you
117+
> can put the two side by side and compare scores."
118+
119+
### 4:10–4:40 — Engineering quality
120+
121+
```bash
122+
just unsafe
123+
```
124+
125+
> "Zero runtime dependencies, matching fuse.js's own design. `mypy --strict`
126+
> clean. Zero casts, zero `type: ignore`, zero bare excepts. Twenty entries in
127+
> DECISIONS.md, each with the evidence behind it."
128+
129+
Scroll `DECISIONS.md` for two seconds — don't read it.
130+
131+
### 4:40–5:00 — Close on the honest number
132+
133+
> "One number I'm not hiding: fuse.js is about 13 times faster. V8 JITs the
134+
> Bitap inner loop, CPython interprets it. The port's value is reach and
135+
> parity, not speed, and the benchmark methodology is in the repo.
136+
>
137+
> Everything you saw is one command each: `just test`, `just compat`,
138+
> `just fuzz`. Thanks."
139+
140+
---
141+
142+
## Cheat sheet — the six numbers
143+
144+
| | |
145+
|---|---|
146+
| Original suite | **285 / 297** (95.96%), files unmodified |
147+
| Fuzz | **0** structural divergences in **51,569** cases |
148+
| Score agreement | ~**1e-13** relative (worst 8.5e-14) |
149+
| Tie-order flips | **8 / 51,569** (0.016%) — disclosed |
150+
| Escape hatches | **0** |
151+
| Speed | fuse.js **~13x** faster — stated, not buried |
152+
153+
## If you make slides
154+
155+
Six slides, one idea each. Don't read them aloud.
156+
157+
1. **The gap** — `rapidfuzz` = strings. Elasticsearch = a server. Nothing in
158+
between. fuse.js is the missing middle, and it's JS-only.
159+
2. **What it is** — Bitap + weighted keys + extended queries + IDF token search.
160+
3. **285/297** — the original JS suite, unmodified, running against Python.
161+
4. **0 / 51,569** — differential fuzzing against the live oracle.
162+
5. **The 1-ULP wall** — one honest limit, with the consequence disclosed.
163+
6. **13x slower, 0 dependencies, 0 escape hatches** — the trade, stated plainly.
164+
165+
## Recording notes
166+
167+
- OBS or the built-in screen recorder; 1080p is plenty.
168+
- Terminal only. No talking-head, no intro animation — you have 300 seconds.
169+
- If `just fuzz 60` is too long to sit through, run `just fuzz 20` on camera
170+
and say you shortened it; the committed `fuzz/log.txt` is the 60-second run.
171+
- Upload unlisted to YouTube, paste the link in the form.

‎README.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,24 @@ just demo --interactive # ...then a live search prompt
7171
just playground # serve the browser playground locally
7272
```
7373

74+
### Worked examples
75+
76+
Three scripts in [`examples/`](./examples/) that use the port to solve a real
77+
problem rather than to show off an API. Each documents the option choices it
78+
made and why, and the numbers in the commentary were measured, not guessed.
79+
80+
| | What it does |
81+
|---|---|
82+
| [`ticket_triage.py`](./examples/ticket_triage.py) | Routes messy free-text support tickets to a runbook, with cutoffs for auto-route / suggest / escalate. Shows why long queries need token search, and why IDF misleads on a small corpus. |
83+
| [`reconcile.py`](./examples/reconcile.py) | Fuzzy-joins two record sets after a migration drops the key — `ACME CORPORATION LTD` vs `Acme Corp. Limited`. Reports matched, needs-review, and missing in both directions. |
84+
| [`search_json.py`](./examples/search_json.py) | A general CLI: fuzzy-search any JSON or JSONL file, with inferred or explicit keys, extended operators and highlighted output. |
85+
86+
```bash
87+
python examples/ticket_triage.py
88+
python examples/reconcile.py
89+
python examples/search_json.py tests/original/test/fixtures/books.json "ste ham"
90+
```
91+
7492
## Build and run
7593

7694
One command:

0 commit comments

Comments
 (0)