@zakkster/lite-bake-stream 1.3.0 → 1.3.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 +12 -0
- package/README.md +1 -1
- package/SPEC.md +2 -2
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/FileIngest.js +1 -1
- package/src/MultiReader.js +1 -1
- package/src/PreserveReader.js +1 -1
- package/src/PreserveTokenizer.js +1 -1
- package/src/PreserveWriter.js +1 -1
- package/src/RangeReader.js +1 -1
- package/src/Reader.js +1 -1
- package/src/Split.js +1 -1
- package/src/StringTable.js +1 -1
- package/src/Tokenizer.js +1 -2
- package/src/Writer.js +1 -1
- package/src/index.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
|
+
## [1.3.1] -- 2026-09-01
|
|
6
|
+
|
|
7
|
+
M3 remainder (BS-05) -- the UTF-8 door ends the promise-A/behavior-B split with a measured decision. Option A (validate at the tokenizer, refuse invalid UTF-8 with `E_INVALID_UTF8`) was built, proven correctness-green (460/460, torture fast 42/42), and rejected on its pre-committed budget: unicode-heavy throughput regressed 229.7 -> 213.1 MB/s (-7.2%, over the 3% ceiling), because the baseline scan bulk-copies `>= 0x80` bytes with zero inspection so validation is pure added cost, while ASCII stayed within noise. SPEC 5.5 is instead rewritten to match the long-standing behavior (documented-permissive), and the dead code is removed. No bytes move at runtime. See decisions/0006-utf8-door.md for the before/after numbers and the rejected option. Suite: 453 tests / 453 pass / 0 fail / 0 todo. Torture: 42/42 fast, 44/44 full, arrayBuffers growth 0. Inverted mutation check: all 49 battery and pin tests pass on baseline src as well -- zero behavior change, proven.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- SPEC 5.5 and SPEC 7's U32 row rewritten to documented-permissive: string bytes between the quotes are stored byte-exact through U32 lanes regardless of UTF-8 validity; invalid sequences are not a parse error. `get()`/`getString()` decode with replacement (U+FFFD); `shardStringTable(s).bytesAt(i)` returns the exact stored bytes, the schema-mode twin of `PreserveReader.getBytes(i)`. This is a documentation-and-dead-code change only -- no runtime behavior changed, no new public surface (the accessor already existed).
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- BS-05: the SPEC no longer promises a UTF-8 parse error the tokenizer never enforced, and `Tokenizer.js` no longer declares an unreachable `E_INVALID_UTF8` code. The byte-exact string contract is now stated truthfully: invalid bytes round-trip byte-exact and decode with U+FFFD, in schema mode exactly as in preserve mode. Lone-surrogate escapes still refuse with `E_UNPAIRED_SURROGATE` (an escape-grammar rule, unrelated to input-UTF-8 validity).
|
|
16
|
+
|
|
5
17
|
## [1.3.0] -- 2026-09-01
|
|
6
18
|
|
|
7
19
|
M2 -- a container is verified at the door or refused at the door. The four readers (`Reader`, `PreserveReader`, `RangeReader`, `MultiReader`) now agree with each other and with the `Writer` about the bytes between them; every malformed container names its refusal with a code, and a standalone SPEC byte-checker (reads SPEC.md offsets only, imports nothing from `src/`) is the contract's executable form. All new validation runs at open/parse/construction time -- the `get`/`syncRange`/`findShards` row loops and both tokenizer byte loops are byte-identical. Suite: 432 tests / 431 pass / 0 fail / 1 todo. Torture: 37/37 fast, 39/39 full, arrayBuffers growth 0. Mutation check: all 52 door tests fail on source revert; all 23 behavior-unchanged pins hold.
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
> Streaming byte-level JSON compiler for [`@zakkster/lite-bake`](https://github.com/PeshoVurtoleta/lite-bake). Zero-GC, tree-shakeable, gigabyte-scale.
|
|
15
15
|
|
|
16
|
-
**Status:** v1.3.
|
|
16
|
+
**Status:** v1.3.1. LBK1 format frozen at `format_version: 1`. Qualified on an 8 GB soak with zero GC and byte-exact preservation across 590 million cells.
|
|
17
17
|
|
|
18
18
|
## Two modes, one API
|
|
19
19
|
|
package/SPEC.md
CHANGED
|
@@ -274,7 +274,7 @@ The boundary is exercised explicitly by `test/NumericBoundary.test.js`, which pi
|
|
|
274
274
|
|
|
275
275
|
### 5.5 String semantics (v1)
|
|
276
276
|
|
|
277
|
-
-
|
|
277
|
+
- String bytes between the quotes are stored byte-exact through U32 lanes, regardless of UTF-8 validity. Invalid sequences are **not** a parse error; the prior rule declaring them one (and its `E_INVALID_UTF8` code) is withdrawn. `get()` / `getString()` decode with replacement (U+FFFD); `shardStringTable(s).bytesAt(i)` returns the exact stored bytes, as `PreserveReader.getBytes(i)` does in preserve mode.
|
|
278
278
|
- All standard JSON escapes are supported: `\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r`, `\t`, `\uXXXX`.
|
|
279
279
|
- Surrogate pairs (`\uD800`..`\uDBFF` followed by `\uDC00`..`\uDFFF`) are combined and emitted as UTF-8.
|
|
280
280
|
- Unpaired surrogates are a parse error.
|
|
@@ -334,7 +334,7 @@ Given source NDJSON `S` and a schema `Σ` (either explicit or inferred), the LBK
|
|
|
334
334
|
| :-- | :-- | :-- |
|
|
335
335
|
| JSON number in fast-path domain (≤15 sig digits, `|exp| ≤ 22`) | F64 | **bit-exact IEEE 754 double** |
|
|
336
336
|
| JSON number in slow-path domain | F64 | within 1 ULP of the correctly-rounded value |
|
|
337
|
-
| JSON string (any valid UTF-8) | U32 | **byte-exact
|
|
337
|
+
| JSON string (any bytes, valid UTF-8 or not) | U32 | **byte-exact bytes; validity not asserted** |
|
|
338
338
|
| JSON `true` / `false` / `null` | F64 | `1` / `0` / `0` (documented coercion) |
|
|
339
339
|
| absent field (missing in source) | F64 | `0` (default) |
|
|
340
340
|
| absent field | U32 | `""` (index 0 is the reserved empty-string entry) |
|
package/llms.txt
CHANGED
|
@@ -8,13 +8,13 @@ Ingest gigabyte-scale JSON (top-level array or NDJSON) into the `lite-bake` LBK1
|
|
|
8
8
|
|
|
9
9
|
## Status
|
|
10
10
|
|
|
11
|
-
v1.3.
|
|
11
|
+
v1.3.1 — stable. LBK1 format frozen at `format_version: 1`. Qualified on an 8 GB soak (M1 MacBook Pro): 98.37M rows, 4.89 GB container, zero major GC, zero minor GC, 499 KB total heap allocation, 590.21M cells verified byte-exact, zero mismatches. Tokenizer benches at 222-237 MB/s (~55% of JSON.parse, with no object graph allocated).
|
|
12
12
|
|
|
13
13
|
Public API follows semver from 1.0.0. Future additions (I64 lane, columnar payload mode, container-level string table) land via the format's forward-compat seams -- `min_reader_version` on ShardEntry, reserved FieldDescriptor flags, the `metadata_off` block wrapper -- without a format_version bump.
|
|
14
14
|
|
|
15
15
|
See SPEC.md for the LBK1 container format, section 3.6 for zone maps, section 4.3 for the reserved field flags.
|
|
16
16
|
|
|
17
|
-
## Public API (v1.3.
|
|
17
|
+
## Public API (v1.3.1)
|
|
18
18
|
|
|
19
19
|
Two ingest modes share one top-level API:
|
|
20
20
|
|
package/package.json
CHANGED
package/src/FileIngest.js
CHANGED
|
@@ -27,7 +27,7 @@ import { PreserveWriter } from './PreserveWriter.js';
|
|
|
27
27
|
import { PreserveReader } from './PreserveReader.js';
|
|
28
28
|
import { checkOpts } from './Opts.js';
|
|
29
29
|
|
|
30
|
-
export const VERSION = '1.3.
|
|
30
|
+
export const VERSION = '1.3.1';
|
|
31
31
|
|
|
32
32
|
const U32_MAX = 4294967295;
|
|
33
33
|
const INGEST_OPTS = {
|
package/src/MultiReader.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
// M_ROW_OUT_OF_RANGE - rowIdx >= totalRows
|
|
26
26
|
// M_TOO_MANY_ROWS - cumulative row count exceeds Number.MAX_SAFE_INTEGER
|
|
27
27
|
|
|
28
|
-
export const VERSION = '1.3.
|
|
28
|
+
export const VERSION = '1.3.1';
|
|
29
29
|
|
|
30
30
|
export class MultiReaderError extends Error {
|
|
31
31
|
constructor(code, msg) { super(msg); this.code = code; this.name = 'MultiReaderError'; }
|
package/src/PreserveReader.js
CHANGED
package/src/PreserveTokenizer.js
CHANGED
package/src/PreserveWriter.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import { checkOpts } from './Opts.js';
|
|
20
20
|
|
|
21
|
-
export const VERSION = '1.3.
|
|
21
|
+
export const VERSION = '1.3.1';
|
|
22
22
|
|
|
23
23
|
export class PreserveWriterError extends Error {
|
|
24
24
|
constructor(code, msg) { super(msg); this.code = code; this.name = 'PreserveWriterError'; }
|
package/src/RangeReader.js
CHANGED
package/src/Reader.js
CHANGED
package/src/Split.js
CHANGED
|
@@ -37,7 +37,7 @@ import { Reader, ReaderError } from './Reader.js';
|
|
|
37
37
|
import { StringTable } from './StringTable.js';
|
|
38
38
|
import { checkOpts } from './Opts.js';
|
|
39
39
|
|
|
40
|
-
export const VERSION = '1.3.
|
|
40
|
+
export const VERSION = '1.3.1';
|
|
41
41
|
|
|
42
42
|
const LF = 0x0A;
|
|
43
43
|
const CONTAINER_HEADER_BYTES = 48;
|
package/src/StringTable.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
// and at every reset(), so an absent U32 row cell (which is 0) decodes as ""
|
|
21
21
|
// rather than aliasing the shard's first-interned string (SPEC 3.3, SPEC 7).
|
|
22
22
|
|
|
23
|
-
export const VERSION = '1.3.
|
|
23
|
+
export const VERSION = '1.3.1';
|
|
24
24
|
|
|
25
25
|
const EMPTY_SLOT = 0xFFFFFFFF; // MUST be unsigned; typed-array reads are unsigned
|
|
26
26
|
const INITIAL_BLOB_BYTES = 64 * 1024;
|
package/src/Tokenizer.js
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
// E_INVALID_ESCAPE - unknown \ sequence
|
|
11
11
|
// E_INVALID_HEX - non-hex digit in \uXXXX
|
|
12
12
|
// E_UNPAIRED_SURROGATE - lone high/low surrogate in \u escape
|
|
13
|
-
// E_INVALID_UTF8 - malformed UTF-8 byte sequence
|
|
14
13
|
// E_NUMBER_OVERFLOW - number magnitude exceeds F64 range
|
|
15
14
|
// E_NUMBER_INVALID - malformed number literal
|
|
16
15
|
// E_KEYWORD_MISMATCH - true/false/null spelled wrong
|
|
@@ -24,7 +23,7 @@
|
|
|
24
23
|
|
|
25
24
|
import { checkOpts } from './Opts.js';
|
|
26
25
|
|
|
27
|
-
export const VERSION = '1.3.
|
|
26
|
+
export const VERSION = '1.3.1';
|
|
28
27
|
|
|
29
28
|
const U32_MAX = 4294967295;
|
|
30
29
|
const TOKENIZER_OPTS = {
|
package/src/Writer.js
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
import { StringTable } from './StringTable.js';
|
|
37
37
|
import { checkOpts } from './Opts.js';
|
|
38
38
|
|
|
39
|
-
export const VERSION = '1.3.
|
|
39
|
+
export const VERSION = '1.3.1';
|
|
40
40
|
|
|
41
41
|
const U32_MAX = 4294967295;
|
|
42
42
|
// Post-finalize sentinel for _recordDepth. Chosen = 2 so every post-finalize
|