pikelet-wasm 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +340 -4
- package/NOTICE +5 -0
- package/README.md +226 -475
- package/complete/builder.d.ts +4 -4
- package/complete/builder.mjs +26 -9
- package/complete/encoder-kernels/encoder.node.wasm +0 -0
- package/complete/encoder-kernels/encoder.wasm +0 -0
- package/complete/fusion.mjs +72 -0
- package/complete/index.d.ts +34 -7
- package/complete/index.mjs +258 -129
- package/complete/inline-transformer.mjs +119 -10
- package/complete/lexical.mjs +11 -11
- package/complete/retrieval-abstention.mjs +136 -31
- package/complete/sources.mjs +22 -1
- package/complete/wordpiece.mjs +22 -0
- package/dist/engine.js +1 -1
- package/dist/engine.scalar.js +1 -1
- package/dist/engine.scalar.wasm +0 -0
- package/dist/engine.wasm +0 -0
- package/package.json +47 -82
- package/{pancake-artifact-common.js → src/artifact/pikelet-artifact-common.js} +42 -42
- package/{pancake-artifact-range.js → src/artifact/pikelet-artifact-range.js} +43 -36
- package/{pancake-artifact-sketch.js → src/artifact/pikelet-artifact-sketch.js} +105 -68
- package/{pancake-artifact.d.ts → src/artifact/pikelet-artifact.d.ts} +11 -11
- package/{pancake-artifact.js → src/artifact/pikelet-artifact.js} +10 -10
- package/{pancake-core.js → src/core/pikelet-core.js} +141 -140
- package/{pancake-errors.js → src/errors/pikelet-errors.js} +9 -8
- package/{pancake.d.ts → src/pikelet.d.ts} +55 -55
- package/{pancake.js → src/pikelet.js} +47 -47
- package/{pancake.node.mjs → src/pikelet.node.mjs} +49 -49
- package/{pancake.web.d.ts → src/pikelet.web.d.ts} +13 -13
- package/{pancake.web.mjs → src/pikelet.web.mjs} +24 -24
- package/{pancake.workerd.mjs → src/pikelet.workerd.mjs} +22 -22
- /package/{pancake-loader.js → src/loader/pikelet-loader.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,15 +1,350 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
Release notes for the two published packages in this repository,
|
|
4
|
-
`pikelet-wasm` (engine + artifact readers/builders) and
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
`pikelet-wasm` (engine + artifact readers/builders) and `pikelet` (the
|
|
5
|
+
CLI: compile, mcp, doctor, scaffold; plus the Docusaurus plugin).
|
|
6
|
+
Through 0.6.0 these were published as `pancake-wasm` and
|
|
7
|
+
`create-pancake-search`; both old names are deprecated pointers. Both
|
|
8
|
+
packages are pre-1.0: a minor bump may carry breaking changes, and each entry lists them
|
|
7
9
|
first.
|
|
8
10
|
|
|
11
|
+
## 0.8.1 — `pikelet-wasm`
|
|
12
|
+
|
|
13
|
+
Security release, cut from `main` ahead of the rest of the unreleased
|
|
14
|
+
backlog below. `pikelet` is unchanged at 0.8.1 and picks this up through its
|
|
15
|
+
`^0.8.0` dependency range.
|
|
16
|
+
|
|
17
|
+
### Security
|
|
18
|
+
|
|
19
|
+
- **A `.pikelet` can no longer overflow the encoder's WASM heap through an
|
|
20
|
+
out-of-range `maxTokens`.** `complete/inline-transformer.mjs` sized the
|
|
21
|
+
kernel's ids and hidden-state buffers from the artifact's own encoder
|
|
22
|
+
declaration, clamped with `Math.min(declaration.maxTokens || 512, 512)` —
|
|
23
|
+
an upper bound only. A pack declaring `maxTokens: 1` made the windowing
|
|
24
|
+
arithmetic (`windowLen = maxSeq - 2`) negative, so `interior.slice(w *
|
|
25
|
+
windowLen, (w + 1) * windowLen)` returned nearly the whole token sequence
|
|
26
|
+
and the forward pass wrote past both allocations: a 60-token query wrote
|
|
27
|
+
about 92 KB into a 1,536-byte buffer. `maxTokens` is now validated as an
|
|
28
|
+
integer in `[8, 512]` at parse, before anything is allocated, `maxSeq` is
|
|
29
|
+
clamped on both sides, and both call sites assert the window fits.
|
|
30
|
+
|
|
31
|
+
This fired at **mount**, before any query: the reader awaits the encoder
|
|
32
|
+
for a non-deferred query-interp segment (and prefetches it otherwise), and
|
|
33
|
+
the declaration's own `testVectors` are verified after the buffers exist,
|
|
34
|
+
so a long test vector was itself a trigger. Every integrity check passed,
|
|
35
|
+
because the attacker authored the file and its digests bind their bytes.
|
|
36
|
+
|
|
37
|
+
Affects anyone who mounts a `.pikelet` they did not compile — the format's
|
|
38
|
+
intended use, since packs are distributed and range-read from URLs. The
|
|
39
|
+
write is confined to the encoder's WASM linear memory and does not reach
|
|
40
|
+
host JavaScript objects, which is why it is rated high rather than
|
|
41
|
+
critical. Upgrade to get the bound; there is no workaround short of not
|
|
42
|
+
mounting third-party packs.
|
|
43
|
+
|
|
9
44
|
## Unreleased
|
|
10
45
|
|
|
11
46
|
### Breaking / compatibility
|
|
12
47
|
|
|
48
|
+
- **The `PANCAKE_ENCODER_WEIGHTS_URL`, `PANCAKE_SEARCH_EMBED_WORKERS`,
|
|
49
|
+
`PANCAKE_SEARCH_STUB_EMBEDDINGS`, and `PANCAKE_SEARCH_PYTHON`
|
|
50
|
+
environment variable fallbacks are removed.** 0.7.0 introduced
|
|
51
|
+
`PIKELET_ENCODER_WEIGHTS_URL` / `PIKELET_EMBED_WORKERS` while still
|
|
52
|
+
honoring the old names; those old names no longer work. Use
|
|
53
|
+
`PIKELET_ENCODER_WEIGHTS_URL`, `PIKELET_EMBED_WORKERS`,
|
|
54
|
+
`PIKELET_SEARCH_EMBED_WORKERS`, `PIKELET_SEARCH_STUB_EMBEDDINGS`, and
|
|
55
|
+
`PIKELET_SEARCH_PYTHON`. Pre-1.0; scripts/CI referencing the old
|
|
56
|
+
names need updating.
|
|
57
|
+
- **`pikelet-wasm` declares `engines.node >=18`** (was `>=16`).
|
|
58
|
+
`complete/sources.mjs` uses the global `fetch`, which Node 16 does not
|
|
59
|
+
have; CI tests 18, 20 and 22. The `pikelet` CLI is unchanged at
|
|
60
|
+
`>=20`.
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
|
|
64
|
+
- **The repository is an npm workspace with the two packages under
|
|
65
|
+
`packages/`.** `packages/pikelet-wasm/` holds the published library —
|
|
66
|
+
entrypoints and readers under `src/` (`src/core`, `src/artifact`,
|
|
67
|
+
`src/errors`, `src/loader`), the C++ engine under `engine/`
|
|
68
|
+
(formerly the root `src/`), `complete/`, `native/` and the four tracked
|
|
69
|
+
`dist/` build outputs; `packages/pikelet/` holds the CLI (formerly
|
|
70
|
+
`pikelet/`). The root `package.json` is a private workspace root
|
|
71
|
+
carrying the test ladder and dev tooling; `npm install` links
|
|
72
|
+
`node_modules/pikelet-wasm` and `node_modules/pikelet` to the checkouts,
|
|
73
|
+
so tests, benchmarks and examples import `pikelet-wasm` exactly as
|
|
74
|
+
consumers do, and the CLI's and Docusaurus plugin's "repo root is
|
|
75
|
+
pikelet-wasm" resolution fallbacks are gone. The published tarball's
|
|
76
|
+
file list is unchanged: `main`/`types`/`exports` point into `src/`, and
|
|
77
|
+
`CHANGELOG.md`, `LICENSE`, `NOTICE` and `README.md` are staged into the
|
|
78
|
+
package by an npm `prepack` script instead of being duplicated in the
|
|
79
|
+
tree. `run_tests.js` lives at `test/run_tests.js`; the engine benchmark
|
|
80
|
+
scripts, whose relative requires had been left pointing one directory
|
|
81
|
+
too high by the benchmarks move, resolve the package again.
|
|
82
|
+
- **Examples renamed, not renumbered**: `examples/04-static-wiki-pack` →
|
|
83
|
+
`examples/static-wiki-pack`, `examples/05-one-file-search` →
|
|
84
|
+
`examples/one-file-search`, `examples/06-mcp-knowledge-pack` →
|
|
85
|
+
`examples/mcp-knowledge-pack`; `npm run demo:veyra` and the committed
|
|
86
|
+
`veyra.mcp.json` follow. The raw browser demo page moves from `dist/`
|
|
87
|
+
to `examples/technical-demo.html` (loads `../dist/engine.js`), and
|
|
88
|
+
`docs/SYSTEM_DESIGN.md` is `docs/architecture.md`. The wiki playground's
|
|
89
|
+
built bundle and deployment are unchanged.
|
|
90
|
+
- **README trimmed to the pitch, quickstart, live demo, numbers and
|
|
91
|
+
links** (577 → ~340 lines). Its long-form sections moved verbatim to
|
|
92
|
+
`docs/how-a-query-runs.md` (what is inside the file, compression cost,
|
|
93
|
+
remote execution, integrity), `docs/veyra-ablation.md` and
|
|
94
|
+
`docs/why-a-file.md`, linked from a new "Deeper dives" section.
|
|
95
|
+
- **Benchmarks consolidated under `benchmarks/`**: `bench/beir` →
|
|
96
|
+
`benchmarks/beir`, `bench/range-proof` → `benchmarks/range-proof`, the
|
|
97
|
+
engine suite (formerly `benchmarks/`) → `benchmarks/engine`, and the
|
|
98
|
+
committed release runs (formerly `benchmark_results/release`) →
|
|
99
|
+
`benchmarks/results`, with raw runs under the ignored
|
|
100
|
+
`benchmarks/results/raw`. `npm run bench` runs `benchmarks/engine/run.js`.
|
|
101
|
+
Nothing published changes.
|
|
102
|
+
- **Abstention calibration is fit against a different negative pool.**
|
|
103
|
+
Hard negatives are now ablation pairs (a verified positive's own text,
|
|
104
|
+
scored with its source excluded), entity swaps (a proper noun replaced
|
|
105
|
+
by a corpus entity that never co-occurs with it), and held-out-document
|
|
106
|
+
questions (title questions scored with that document excluded). A fit
|
|
107
|
+
whose `d0` weight comes out non-negative ships `unscored` instead. The
|
|
108
|
+
calibration summary (`fitAuc`, `cvAuc`, `cvAucHard`, per-class counts)
|
|
109
|
+
is persisted in the evaluation segment and reported by `verify_pack`;
|
|
110
|
+
golden queries are sampled from retrieval-verified positives. Packs
|
|
111
|
+
rebuilt with this calibrator get a different fit and therefore a
|
|
112
|
+
different identity; existing packs are unaffected.
|
|
113
|
+
- **`query()` returns `grounding`** — `{ recordId, coverage, covered,
|
|
114
|
+
uncovered }`: which of the query's content words the best passage
|
|
115
|
+
restates and which no passage contains — and each result carries
|
|
116
|
+
`vectorRank`, `lexicalRank` and `fusedRank`. A verbatim match of three
|
|
117
|
+
or more consecutive query words is pinned to rank 1 ahead of semantic
|
|
118
|
+
near-misses. Phrase pinning and the coverage term now hydrate their
|
|
119
|
+
candidates in one batch.
|
|
120
|
+
- **MCP `search` ships results under a `"none"` verdict by default**,
|
|
121
|
+
with a note, instead of withholding them (`showAbstained: false`
|
|
122
|
+
restores withholding); packs without a fitted calibrator get an
|
|
123
|
+
`unscoredWarning`. Each section carries `grounding`. The tool
|
|
124
|
+
description and `server/discover` instructions describe `matchQuality`
|
|
125
|
+
as how directly the text restates the question, not whether the answer
|
|
126
|
+
is present, and tell the caller to treat a queried-for term in
|
|
127
|
+
`grounding.uncovered` as unestablished and to search again for the
|
|
128
|
+
second hop of a chained question.
|
|
129
|
+
- **The reader no longer reads `coverage.useMaxSim`**; the word-level
|
|
130
|
+
semantic grounding path is removed rather than left dormant (a pack
|
|
131
|
+
with the flag set was measured at 1.5–4.6 s per query).
|
|
132
|
+
- `scripts/calibration-harness.mjs` reports false-abstention and
|
|
133
|
+
false-answer rates on labeled question sets; the sets live under
|
|
134
|
+
`test/relevance/`.
|
|
135
|
+
- Public browser playground for the Wikipedia pack, with an ablation
|
|
136
|
+
tab.
|
|
137
|
+
|
|
138
|
+
- **`pikelet-wasm/complete` exports `fuseCandidates()` and
|
|
139
|
+
`FUSION_DEFAULTS`.** The hybrid rank-fusion rule (reciprocal-rank fusion
|
|
140
|
+
of the exact-reranked vector order with the BM25 order) is one function
|
|
141
|
+
the reader, the calibrator (`calibrate.mjs`, which fits coverage on the
|
|
142
|
+
fused top passage) and the BEIR ladder (`query-E.mjs`) all call, instead
|
|
143
|
+
of three copies of the arithmetic. It takes `{ rrfK, lexicalWeight,
|
|
144
|
+
guardMargin }`.
|
|
145
|
+
- **Hybrid fusion weights the lexical rank at 0.5 and keeps a confident
|
|
146
|
+
vector top-1 in place.** `FUSION_DEFAULTS` is now `{ rrfK: 60,
|
|
147
|
+
lexicalWeight: 0.5, guardMargin: 0.05 }`: the BM25 rank term counts half
|
|
148
|
+
as much as the vector rank term, and when the vector top-1 leads the
|
|
149
|
+
top-2 by at least 5% of its own distance it keeps rank 1 regardless of
|
|
150
|
+
fusion. Under equal weights any record present in both lists outranked a
|
|
151
|
+
vector-only rank 1 (`1/(60+v) + 1/(60+l) > 1/60` for every finite `v`),
|
|
152
|
+
so a query whose terms match many chunks — a character's name in a
|
|
153
|
+
novel — filled the top ranks with term matches and buried the passage
|
|
154
|
+
the encoder placed first. Measured with the evidence-rank report and the
|
|
155
|
+
fusion simulator (`test/relevance/README.md`): evidence in the top 3 on
|
|
156
|
+
Pride & Prejudice 36 → 42 of 157 direct questions, internal-docs
|
|
157
|
+
paraphrases 19 → 21 of 24, Veyra direct 19 → 20 of 20 and multihop
|
|
158
|
+
17 → 18 of 20; BEIR E by fused rank scifact nDCG@10 0.694 → 0.699
|
|
159
|
+
(recall@10 0.827 → 0.853), nfcorpus 0.3345 → 0.3359, arguana unchanged.
|
|
160
|
+
Verdicts on packs calibrated under the old rule move the same way (false
|
|
161
|
+
answers: internal-docs 10 → 9, Pride & Prejudice 74 → 66, Veyra 13 → 13);
|
|
162
|
+
a Veyra pack recalibrated under the new rule fits at cvAUC 0.890 (was
|
|
163
|
+
0.870). Packs need no rebuild to get the new ranking.
|
|
164
|
+
### Fixed
|
|
165
|
+
|
|
166
|
+
- **Engine constructors validate their configuration.** `pikelet_init`
|
|
167
|
+
(WASM and the native addon) passed caller-supplied `dims`, `M` and
|
|
168
|
+
`max_elements` straight into the index constructors. `M = 1` made the
|
|
169
|
+
level multiplier `1/log(1) = +inf`, whose conversion to an integer on
|
|
170
|
+
the first insert is undefined behaviour, and `max_elements * dims` or
|
|
171
|
+
`max_elements * M0` could wrap a 32-bit `size_t` on wasm32 into an
|
|
172
|
+
undersized arena. Both backends now reject `dims` outside 1..65536, `M`
|
|
173
|
+
outside 2..128 (0 still selects the default), `max_elements = 0`, and
|
|
174
|
+
products that do not fit `size_t`; WASM returns `INVALID_HANDLE`, the
|
|
175
|
+
native addon throws a `RangeError` (a C++ exception used to escape the
|
|
176
|
+
N-API boundary and abort the process). `Pikelet.create()` mirrors the
|
|
177
|
+
`dim` ceiling with an `INVALID_ARGUMENT` error, and the native
|
|
178
|
+
`pikelet_import` rejects a non-buffer argument with a `TypeError`
|
|
179
|
+
instead of continuing with a null view while a JS exception is pending.
|
|
180
|
+
- **Artifacts with a NaN or infinite scale/offset are rejected.** A
|
|
181
|
+
producer signs whatever bytes it writes, so a non-finite affine pair in
|
|
182
|
+
a `.pikelet-range` record or a sketch artifact's affine table passed
|
|
183
|
+
every digest check and then made that row's distance non-finite, which
|
|
184
|
+
the result heap never evicts. The range reader rejects the record at
|
|
185
|
+
decode and the sketch reader rejects the table wherever it adopts it,
|
|
186
|
+
both with `SNAPSHOT_INVALID`.
|
|
187
|
+
- **`stripMarkdown` no longer backtracks quadratically on backtick runs.**
|
|
188
|
+
The fenced-block and inline-code regexes took seconds to minutes on a
|
|
189
|
+
line of 40k backticks (each candidate fence length re-scanned the rest
|
|
190
|
+
of the document; each suffix of an inline run was retried). Both are
|
|
191
|
+
replaced by linear scanners with CommonMark's rules: a fence closes on
|
|
192
|
+
the first later fence line of the same character at least as long, an
|
|
193
|
+
unclosed fence runs to the end of the document, and an inline span of N
|
|
194
|
+
backticks closes on the next run of exactly N on the same line, may
|
|
195
|
+
contain runs of other lengths (`` ``a ` b`` ``), and drops one padding
|
|
196
|
+
space from each end. Under the old regexes a shorter closing fence or
|
|
197
|
+
an unclosed one left the block as prose.
|
|
198
|
+
- **Folder ingestion reports what it skips and caps file size.** The walk
|
|
199
|
+
skipped symlinked files and directories silently (Dirents carry lstat
|
|
200
|
+
semantics); it now logs `warn: skipped symlink <path>` for each. Files
|
|
201
|
+
over 16 MiB are skipped with a warning naming the path and the limit
|
|
202
|
+
instead of being read whole into the build, matching the crawl path's
|
|
203
|
+
body cap.
|
|
204
|
+
- **`pikelet rebuild --verbose` parses.** `--verbose` was read as a
|
|
205
|
+
boolean (`verbose: !!flags.verbose`) but was not registered as one, so
|
|
206
|
+
as the last argument it failed with "Missing value for --verbose" and
|
|
207
|
+
before another flag it swallowed that flag as its value.
|
|
208
|
+
- **`verify_pack` surfaces a corrupt evaluation segment.** The MCP tool
|
|
209
|
+
turned any `evaluation()` failure into "no evaluation", reporting 0
|
|
210
|
+
golden queries and 0 probes, all passed, for a pack whose evaluation
|
|
211
|
+
segment failed its hash or did not parse. Those errors now propagate
|
|
212
|
+
as tool errors; a pack with no evaluation segment still reports zero.
|
|
213
|
+
- **Generated Workers no longer echo internal error messages on 5xx.**
|
|
214
|
+
The `pikelet` scaffold's `worker.js` / `worker.artifact.js` templates
|
|
215
|
+
returned `error.message` for every failure, including unexpected ones,
|
|
216
|
+
which can name bundled asset paths and load state. A 5xx now carries
|
|
217
|
+
`{ error: "Internal server error", code }` and the original error goes
|
|
218
|
+
to the Worker log (`wrangler tail`); 4xx and 503 (`EMBED_UNAVAILABLE`)
|
|
219
|
+
bodies still carry the message. The legacy reference Worker's
|
|
220
|
+
"Invalid JSON body" error no longer appends the parser's message.
|
|
221
|
+
Projects generated by earlier versions keep their old template.
|
|
222
|
+
- **References the 0.8.0 rename left broken are repaired.** The engine
|
|
223
|
+
benchmark scripts called `native.pancake_*` (the N-API addon exports
|
|
224
|
+
`pikelet_*`); the ANN-Benchmarks adapter imported `pancake_py` (the
|
|
225
|
+
pybind module is `pikelet_py`) and, after the benchmarks move, resolved
|
|
226
|
+
the repo root one level short; `dist/technical-demo.html` and
|
|
227
|
+
`test/ios-smoke.html` called `_pancake_*` WASM exports (the iOS page also
|
|
228
|
+
inlined a pre-rename engine build and used the pre-`ef_search` query
|
|
229
|
+
ABI — regenerated from the current `dist/`); the Docusaurus plugin's
|
|
230
|
+
webpack rule matched `pancake-(artifact|errors).js`, which no longer
|
|
231
|
+
exists, so it never applied; READMEs showed `openPancakeFile`,
|
|
232
|
+
`PancakeRangeArtifact`, `PancakeSketchArtifact` and `PancakeIndex`. The
|
|
233
|
+
scaffold template's UI title and the wiki example page's wordmark and
|
|
234
|
+
GitHub links now say Pikelet. `docs/history.md` records the rename and
|
|
235
|
+
lists what intentionally keeps the old name.
|
|
236
|
+
- **`compact()`'s rebuild path no longer leaves the index half-cleared**
|
|
237
|
+
when a reinsertion fails: the old graph is released only after the
|
|
238
|
+
rebuilt one is complete, so a failed rebuild returns with the index
|
|
239
|
+
unchanged. Previously the next `search`/`insert` read out of bounds.
|
|
240
|
+
- Coverage word rules: possessives (`darcy's`) match plain mentions,
|
|
241
|
+
eleven quantifier/hedge words are stopwords, and numerals are exempt
|
|
242
|
+
from the minimum word length (`Chamber 4` vs `Chamber 5`).
|
|
243
|
+
- Ingest: `**/dir/**` globs no longer substring-match sibling names,
|
|
244
|
+
minified HTML with unquoted attributes chunks correctly, a leading BOM
|
|
245
|
+
no longer breaks frontmatter, numeric entities decode, and
|
|
246
|
+
`stripMarkdown` no longer deletes hyphens, underscores and minus
|
|
247
|
+
signs; merging a section with a child heading keeps its provenance;
|
|
248
|
+
ingestion conformance runs on Windows.
|
|
249
|
+
- Browser verification without a WebCrypto backend fails with a clear
|
|
250
|
+
error instead of an obscure one.
|
|
251
|
+
|
|
252
|
+
## pikelet 0.8.1 — 2026-09-18
|
|
253
|
+
|
|
254
|
+
- `pikelet` records `mcpName: "io.github.mcn92/pikelet"` and ships
|
|
255
|
+
`server.json`, the manifest for the official MCP registry entry
|
|
256
|
+
(`pikelet mcp <pack>`; one required positional argument, any
|
|
257
|
+
`.pikelet` file). No code change.
|
|
258
|
+
|
|
259
|
+
## pikelet-wasm 0.8.0 / pikelet 0.8.0 — 2026-09-14
|
|
260
|
+
|
|
261
|
+
### Breaking / compatibility
|
|
262
|
+
|
|
263
|
+
- **Manifest profile strings are renamed** `pancake-complete-v1/v2` →
|
|
264
|
+
`pikelet-complete-v1/v2`. New builds write the `pikelet-` string;
|
|
265
|
+
readers accept either for the same format version, so every pack
|
|
266
|
+
published before this release keeps opening with its identity
|
|
267
|
+
unchanged. Because the profile string is part of the manifest that
|
|
268
|
+
the identity hashes, **a 0.8.0 compile of the same inputs produces a
|
|
269
|
+
different identity than 0.7.0 did**. This reverses the 0.7.0 note that
|
|
270
|
+
the wire format would keep its pancake-era names.
|
|
271
|
+
- **Published API names are renamed** to their Pikelet forms:
|
|
272
|
+
`PancakeError`/`PANCAKE_ERROR_CODES` → `PikeletError`/
|
|
273
|
+
`PIKELET_ERROR_CODES`, `PancakeIndex` → `PikeletIndex`,
|
|
274
|
+
`PancakeRangeArtifact`/`PancakeSketchArtifact` → `PikeletRangeArtifact`/
|
|
275
|
+
`PikeletSketchArtifact`, `PancakeApi`/`NodePancakeApi` → `PikeletApi`/
|
|
276
|
+
`NodePikeletApi`, `openPancakeFile`/`assemblePancakeFile` →
|
|
277
|
+
`openPikeletFile`/`assemblePikeletFile`. The compatibility aliases are
|
|
278
|
+
dropped. The C ABI's `pancake_*` symbols are `pikelet_*`; the native
|
|
279
|
+
addon source is `native/pikelet_napi.cpp`. The `.pancake-range` and
|
|
280
|
+
`.pancake-sketch` extension conventions are `.pikelet-range` and
|
|
281
|
+
`.pikelet-sketch` (readers dispatch on magic bytes, not extension).
|
|
282
|
+
- **`export()` refuses while deleted vectors are resident.** The snapshot
|
|
283
|
+
format has no deleted flag, so a snapshot taken with ghosts present
|
|
284
|
+
resurrected them on import. C++ `serialize()` throws, the WASM
|
|
285
|
+
`pikelet_export` returns null, the native binding throws; call
|
|
286
|
+
`compact()` first. The JS wrapper already enforced this; the native
|
|
287
|
+
path did not.
|
|
288
|
+
- **`@xenova/transformers` is an optional dependency of `pikelet`.** It
|
|
289
|
+
is needed only by the scaffold (`create`) path; `npm install -g pikelet
|
|
290
|
+
--omit=optional` skips its ~140 MB for `compile`/`mcp`-only use.
|
|
291
|
+
- `pikelet` depends on `pikelet-wasm ^0.8.0`.
|
|
292
|
+
|
|
293
|
+
### Added
|
|
294
|
+
|
|
295
|
+
- **Swappable inline encoder.** `compile --encoder-model
|
|
296
|
+
--encoder-weights --encoder-vocab --encoder-pooling mean|cls
|
|
297
|
+
--encoder-query-prefix --encoder-passage-prefix` records a different
|
|
298
|
+
BERT-shaped model (same hidden size, layers, heads and vocab size as
|
|
299
|
+
MiniLM-L6, e.g. Snowflake `arctic-embed-xs`) as artifact data; CLS
|
|
300
|
+
pooling is honored end to end, and `export_encoder_blob.py` checks the
|
|
301
|
+
architecture before exporting.
|
|
302
|
+
- **The inline-transformer kernel's window is 512 tokens** (was 128).
|
|
303
|
+
Chunks longer than 128 tokens are no longer silently truncated at
|
|
304
|
+
embed time; long chunks cost proportionally more to embed. Existing
|
|
305
|
+
artifacts declaring `maxTokens: 128` open and verify unchanged.
|
|
306
|
+
- **`query({ showAbstained: true })`** returns the retrieval under a
|
|
307
|
+
`"none"` verdict alongside the unchanged `matchQuality`/`confidence`.
|
|
308
|
+
- `examples/06-mcp-knowledge-pack`: compile a corpus, mount it over MCP,
|
|
309
|
+
answer with citations. Engine-reference examples move to
|
|
310
|
+
`examples/legacy/`.
|
|
311
|
+
- `bench/beir/` retrieval-quality ladder (dense, hybrid RRF, lexical-only,
|
|
312
|
+
Arctic-XS configs) and `bench/range-proof/` (dumb static server, MCP
|
|
313
|
+
and headless-LLM proofs of the static-hosting claim).
|
|
314
|
+
- A committed MCP config makes the Veyra demo packs queryable
|
|
315
|
+
interactively; the packs themselves are GitHub release assets fetched
|
|
316
|
+
by `web/veyra-corpus/fetch-veyra.mjs` rather than tracked files.
|
|
317
|
+
- Encoder-conformance fixtures live under `test/fixtures/` instead of
|
|
318
|
+
inside an example.
|
|
319
|
+
|
|
320
|
+
### Fixed
|
|
321
|
+
|
|
322
|
+
- **The abstention verdict no longer depends on the caller's `k`.** The
|
|
323
|
+
scorer windows its inputs to the fixed top-10 the calibrator was fit
|
|
324
|
+
on; at `k=3`, `margin`, `mean10` and coverage were computed over
|
|
325
|
+
fewer candidates than at fit time and flipped verdicts between
|
|
326
|
+
`strong` and `weak` for identical retrieval.
|
|
327
|
+
- **Coverage is scored against the fused (vector + BM25) ranking**
|
|
328
|
+
in both the calibrator and the reader, with the lexical cutoff shared
|
|
329
|
+
between them. Calibration was fit on vector-only signals while the
|
|
330
|
+
reader served hybrid results; on a 2,841-record Wikipedia sample every
|
|
331
|
+
measured false abstention had the correct record at hybrid rank 1–6.
|
|
332
|
+
- `httpRangeSource` treats a `200` whose ETag differs from the pinned
|
|
333
|
+
one as `ARTIFACT_CHANGED` instead of a Range-unsupported host; the
|
|
334
|
+
sketch row-digest floor is 16 bytes (readers still accept 8–32);
|
|
335
|
+
`deserialize()` validates every header field before assigning it; the
|
|
336
|
+
L2 insert/search path rejects non-finite vectors (Cosine already did).
|
|
337
|
+
- `chunkDocs` no longer emits title-only stub records from leading
|
|
338
|
+
undersized sections or attributes a merged chunk to the wrong section.
|
|
339
|
+
- Calibration probes: phrasing diversity across question frames, a
|
|
340
|
+
saturation rail on the hard threshold, and a minimum weak band.
|
|
341
|
+
- `spec/COMPLETE_PROFILE.md` Draft 2 resolves the corpus-compression,
|
|
342
|
+
`sampleQueries` placement and browser-packaging questions.
|
|
343
|
+
|
|
344
|
+
## pikelet-wasm 0.7.0 / pikelet 0.7.0 — 2026-09-02
|
|
345
|
+
|
|
346
|
+
### Breaking / compatibility
|
|
347
|
+
|
|
13
348
|
- **The project is renamed to Pikelet.** Packages: `pancake-wasm` →
|
|
14
349
|
`pikelet-wasm`, `create-pancake-search` → `pikelet` (one CLI:
|
|
15
350
|
`npx pikelet create|compile|doctor|mcp`; the old `npm create
|
|
@@ -392,7 +727,8 @@ first.
|
|
|
392
727
|
- **The v1 spec no longer lists hybrid search as a non-goal**:
|
|
393
728
|
docs/CREATE_PANCAKE_SEARCH_SPEC.md's non-goals entry for "Hybrid BM25 +
|
|
394
729
|
vector scoring" is struck through with a pointer to the shipped lexical
|
|
395
|
-
segment (spec §3.8) and the `query({ retrieval })` modes.
|
|
730
|
+
segment (spec §3.8) and the `query({ retrieval })` modes. (That planning
|
|
731
|
+
document was moved out of the repository on 2026-09-05.)
|
|
396
732
|
- **Section-aware ingestion and chunking.** Markdown/MDX documents are
|
|
397
733
|
parsed into their heading structure before chunking — heading lines are
|
|
398
734
|
recognized only outside code fences, explicit `{#custom-id}` heading ids
|