Skip to content

Commit dd2e306

Browse files
mstrathmanclaude
andcommitted
refactor: architectural and cleanliness pass across the extension
Behavioral fixes (all fail-loud): - content_hash is now actually verified at load, closing the gap the receipts removal left: inline student blobs in predict0_registry_lookup (new return code 2 -> PREDICT_ERR_MODEL_HASH at every caller), URI weights in the onnx session builder (once per cache miss) - distill train_query now enforces the same single-statement + read-only contract as every other inner query (shared predict0_prepare_ro) - predict_register rejects runtime 'tree' (a URI tree row could never be served; students come from distill_predict/distill_forecast) - distill_forecast unknown option keys and student+train_query misuse already rejected; predict() runtime misuse reclassified from MODEL_NOT_FOUND to RUNTIME_UNAVAILABLE, teacher prepare failure to SCHEMA - predict_version() lists the bundled model ids instead of "models":[] Duplication removed: - conformal_quantile: one sort+rank implementation for served intervals and backtest coverage (they must agree) - coerce_ts: one epoch/ISO coercion for collect_series and the aggregate step (these rules drifted once already) - parse_name_list: one parser for group_cols and candidates - register_student, fcst_teacher_flush (was the 50-line FLUSH_SERIES macro with an embedded goto), predict0_json_str_array (was json_arr + parse_str_array), predict0_prepare_ro (pr_prepare now delegates) - PREDICT_MAX_FEAT: one feature cap (was TAB_MAX_FEAT, TREE_MAX_FEAT, and two literal 64s in the onnx backend) Dead code and scars deleted: - receipts-era result hashers (hash_null/int/real/text/row_end, hash_sep, PREDICT_RS), predict0_ulid_new, dead params vars, doubled rc check, 4-for-3 struct initializers (both bopts sites) - predict-receipts.c renamed predict-registry.c (Makefile, amalgamate.py, ci.yml fuzz list, ARCHITECTURE.md) - unprefixed cross-TU student runtime functions (tree_free, mlp_forward, fcst_serialize, ...) prefixed predict0_ -- they were link-time collision bait in the amalgamation/static builds Tests and soaks: - both soak drivers now fail the run on unexpected statement results (they printed and discarded); that surfaced two dead expectations: a stale bare-candidates error (valid since auto became the default) and soak_onnx's two-head block never serving (hour-40 timestamps poisoned the series as non_numeric) -- reseeded with valid datetimes, so the reconstruction path now actually runs under ASan - soak_onnx ported off the removed query-form TVF and de-receipted - corrupt-blob soak/test rows now carry correct content hashes so they reach the deserializers they exist to exercise; tamper coverage added separately (PREDICT_ERR_MODEL_HASH) - test_receipts.py -> test_registry.py, test_collect_errors.py -> test_backtest_errors.py, aggregate-driven selection tests split into test_model_selection.py; shared forecast_doc/anomaly_doc helpers in conftest; wave() deduped into synthetic.py Docs and build: - ARCHITECTURE/SECURITY/RELEASING de-receipted and re-grounded (two calling conventions, the real four-workflow release pipeline) - ~30 stale RFC section references corrected across C, tests, and docs - ci fuzz job now runs `make fuzz` (adds UBSan) instead of a hand-copied file list; fuzz-build links -lm -lpthread -ldl for Linux - .PHONY completed; bindings-dev target refreshes the gitignored dev dylibs; test.sql -> examples/smoke.sql; fuzz seed doc1 regenerated Verified: plain 185 passed, onnx 220 passed, ASan+UBSan core and onnx soaks clean, amalgamation-check clean, website builds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent c642aa5 commit dd2e306

33 files changed

Lines changed: 1173 additions & 1168 deletions

‎.github/workflows/ci.yml‎

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,7 @@ jobs:
106106
steps:
107107
- uses: actions/checkout@v4
108108
- name: Build + run libFuzzer
109-
run: |
110-
make vendor/sqlite3ext.h sqlite-predict.h
111-
clang -std=c99 -g -O1 -fsanitize=fuzzer,address \
112-
-DSQLITE_CORE -DSQLITE_PREDICT_STATIC -DSQLITE_STRICT_SUBTYPE=1 \
113-
-Ivendor/ -I./ \
114-
fuzz/fuzz_predict.c sqlite-predict.c predict-forecast.c \
115-
predict-tabular.c predict-receipts.c predict-distill.c \
116-
predict-student.c \
117-
vendor/sha256.c vendor/sqlite3.c -o fuzz_predict -lm -lpthread -ldl
118-
./fuzz_predict -max_total_time=60 -max_len=512 fuzz/seeds
109+
run: make fuzz
119110

120111
windows:
121112
name: windows (mingw)

‎ARCHITECTURE.md‎

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,37 @@ Source layout:
1717
| `sqlite-predict.c` | entry point, function registration, shared helpers (timestamp parse/format, ULID, options parsing, normal-quantile) |
1818
| `predict-forecast.c` | the `forecast()` and `detect_anomalies()` aggregates, `backtest()`, the expansion TVFs, the statistical models, the native forecast-student serving path, and the shared `collect_series()` helper |
1919
| `predict-tabular.c` | `predict()` vtab, the in-context k-NN model, and dispatch to a runtime backend for registered models |
20-
| `predict-receipts.c` | the model registry (`_predict_models`) and content hashing |
20+
| `predict-registry.c` | the model registry (`_predict_models`) and content hashing |
2121
| `predict-onnx.c` | ONNX runtime backend (opt-in build only); the only file that links onnxruntime |
2222
| `predict-student.c` | the native student **serving** runtime: blob (de)serialization and tree / forest / MLP inference (`predict0_tree_run`). The serve side of the train/serve boundary |
23-
| `predict-student.h` | the shared student-model **format**: the tree/forest/MLP structs and the runtime entry points both sides agree on (RFC §4.1.6) |
23+
| `predict-student.h` | the shared student-model **format**: the tree/forest/MLP structs and the runtime entry points both sides agree on (RFC §4.1.3) |
2424
| `predict-distill.c` | the **training** side: the CART / gradient-boosting / MLP trainers, the `distill_predict()` vtab, and the `distill_forecast()` vtab that fits the forecast student. Builds student blobs that `predict-student.c` serves |
2525
| `predict-internal.h` | shared types, contract constants, error codes, internal prototypes |
2626
| `vendor/sha256.c` | a self-contained FIPS 180-4 SHA-256 |
2727

28-
## Operations are table-valued functions
29-
30-
Each operation is an [eponymous virtual table module][tvf]. Arguments
31-
arrive as hidden columns (`query`, `horizon`, `options`), resolved in
32-
`xBestIndex` and consumed in `xFilter`, which does all the work and
33-
materializes result rows the cursor then walks. This is the same mechanism
34-
SQLite's own `generate_series` uses.
35-
36-
`forecast()` and `detect_anomalies()` share `collect_series()`: prepare and
37-
validate the inner query (read-only, single statement), resolve or infer
38-
the time/value/group columns, and collect rows into per-series buffers.
28+
## Two calling conventions: aggregates and TVFs
29+
30+
The series operations are plain SQL aggregate functions.
31+
`forecast(ts, value, horizon[, options])` and
32+
`detect_anomalies(ts, value[, options])` aggregate over the caller's own
33+
rows: each input row contributes one (ts, value) observation, each
34+
aggregate evaluation (one `GROUP BY` group, or the whole statement) is
35+
one series, and the result is a single JSON document. The
36+
`forecast_rows(doc)` and `anomaly_rows(doc)` table-valued functions
37+
expand that document back into typed rows.
38+
39+
The query-shaped operations (`backtest()`, `predict()`,
40+
`distill_predict()`, `distill_forecast()`) are [eponymous virtual table
41+
modules][tvf] instead. Arguments arrive as hidden columns (a `query`
42+
string plus operation-specific columns such as `horizon` and `options`),
43+
resolved in `xBestIndex` and consumed in `xFilter`, which does all the
44+
work and materializes result rows the cursor then walks. This is the
45+
same mechanism SQLite's own `generate_series` uses.
46+
47+
`collect_series()` (prepare and validate an inner query as read-only and
48+
single-statement, resolve or infer the time/value/group columns, collect
49+
rows into per-series buffers) now serves only `backtest()`, the one
50+
series operation that still takes a query string.
3951

4052
## Models
4153

@@ -66,7 +78,7 @@ a complete registration for the vector case (in-context adds only `target`,
6678
which is a SQL column introspection can't see). An explicit `io_spec`
6779
overrides the derivation. Feature columns map positionally by default (apply
6880
column order); a `features` list switches to name-based mapping. All the JSON
69-
handling — reading the `io_spec`, building the derived one — goes through
81+
handling (reading the `io_spec`, building the derived one) goes through
7082
SQLite's JSON1 (`json_extract`/`json_each`/`json_object`), never a hand-rolled
7183
parser. Both cache one onnxruntime session per (weights, device,
7284
precision), run query rows in batches, and select the execution provider
@@ -87,20 +99,20 @@ teacher's accuracy is usually distillation to a small student.
8799
zero-dependency core. It fits a native student on a training signal,
88100
evaluates it on a held-out fraction, and writes the student into
89101
`_predict_models` as an inline BLOB (`runtime='tree'`, `kind='student'`). By
90-
default the signal is the `target` column of the training query — your
102+
default the signal is the `target` column of the training query: your
91103
labels, or a strong teacher's predictions computed offline and stored in that
92104
column, which is how a 30-second TabFM run becomes a microsecond student. A
93105
`teacher` argument names a registered `predict()` model, which `distill`
94-
re-runs over the rows (aligned by row number) to relabel them first — the way
106+
re-runs over the rows (aligned by row number) to relabel them first, the way
95107
to compress the in-context knn5 into a standalone tree.
96108

97109
Three `student_kind`s exist. `'tree'` and `'gbt'` share the CART trainer;
98110
`'tree'` is a single depth-8 tree. `'gbt'` is a gradient-boosted forest of
99111
shallow trees, and it is the go-to when accuracy matters: it fits each tree to
100112
the loss
101113
gradient but sets each leaf to the **second-order (Newton) step**
102-
`Σg / (Σh + λ)` using the softmax Hessian — the same thing that lifts
103-
XGBoost above a vanilla gradient booster — with shrinkage (a small learning
114+
`Σg / (Σh + λ)` using the softmax Hessian (the same thing that lifts
115+
XGBoost above a vanilla gradient booster), with shrinkage (a small learning
104116
rate over many rounds) doing the regularizing. It is deterministic by
105117
construction: no bootstrap, no feature-sampling, no early-stopping split, so
106118
the student stays reproducible and exactly replayable. Given `proba` and
@@ -118,19 +130,19 @@ a `tree`-runtime model to the native runtime in the same file, which tells a
118130
single tree (`PSTREE` blob) from a forest (`PSGBT` blob) from a net (`PSMLP`
119131
blob) by magic and needs
120132
no onnxruntime. The blob formats are little-endian and normatively specified
121-
and versioned (RFC §4.1.6, `PSTREE01` / `PSGBT01` / `PSMLP01`), so a stored student stays
133+
and versioned (RFC §4.1.3, `PSTREE01` / `PSGBT01` / `PSMLP01`), so a stored student stays
122134
servable across upgrades, snapshots, and forks, and a serving-only module can
123135
execute a blob it never trained. They are rigorously bounds-checked on read,
124136
because the registry is
125-
writable by any SQL caller (RFC §6.2) — a hand-crafted blob is rejected,
137+
writable by any SQL caller (RFC §6.2): a hand-crafted blob is rejected,
126138
never crashed on. The student is native and deterministic, like the stat
127139
models.
128140

129141
Forecasting has its own student. `distill_forecast()` (`predict-distill.c`)
130142
fits a regression MLP that maps an instance-normalized context window of `nfeat`
131143
recent values to `nquant` quantiles per horizon step, distilled from a teacher's
132144
forecasts over sliding windows. It is stored as a fourth student blob (`PSFCST`,
133-
RFC §4.1.6) and served not by `predict()` but by `forecast()`
145+
RFC §4.1.3) and served not by `predict()` but by `forecast()`
134146
(`predict-forecast.c`), which extracts the most recent window, normalizes it by
135147
its own mean and standard deviation (so one student serves series of any
136148
magnitude), applies the net, and de-normalizes. When the student carries a
@@ -152,12 +164,13 @@ fp16 inference is not bit-reproducible across machines (different hardware
152164
and kernels round differently). Cross-machine, cross-backend bit-equality
153165
is never claimed (see `benchmarks/notes.md`).
154166

155-
## Deviations from the spec
167+
## Spec alignment
156168

157-
The implementation surfaced amendments queued for the design spec: the
158-
`ts-stat`/`tabular-stat` model kinds, aggregate-form `forecast`/
159-
`detect_anomalies` as the one calling convention for series operations,
160-
the removal of receipts, and null option values meaning "key omitted."
161-
These are noted at the top of the files that introduce them.
169+
The design spec (RFC 0005) has been amended to match the implemented
170+
surface: the `ts-stat`/`tabular-stat` model kinds, the aggregate calling
171+
convention for `forecast` and `detect_anomalies`, null option values
172+
meaning "key omitted," and the removal of receipts (that design is
173+
preserved in the RFC's Appendix D). Section references in this document
174+
follow the amended numbering.
162175

163176
[tvf]: https://www.sqlite.org/vtab.html#tabfunc2

‎Makefile‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ prefix?=dist
3737

3838
TARGET_LOADABLE=$(prefix)/predict0.$(LOADABLE_EXTENSION)
3939

40-
OBJS=sqlite-predict.c predict-forecast.c predict-receipts.c predict-tabular.c predict-student.c predict-distill.c vendor/sha256.c
40+
OBJS=sqlite-predict.c predict-forecast.c predict-registry.c predict-tabular.c predict-student.c predict-distill.c vendor/sha256.c
4141
ONNX_OBJS=$(OBJS) predict-onnx.c
4242

4343
# onnxruntime is a build+runtime dependency of the loadable-onnx variant
@@ -117,7 +117,7 @@ test-onnx: loadable-onnx
117117

118118
# ASan+UBSan on the C soak driver (standalone executable: no DYLD
119119
# injection needed, macOS SIP strips it for system binaries anyway).
120-
# Covers every operation, receipts, replay, and the error paths.
120+
# Covers every operation and the error paths.
121121
test-asan: vendor/sqlite3ext.h sqlite-predict.h
122122
mkdir -p $(prefix)
123123
clang -std=c99 -g -O1 -fsanitize=address,undefined \
@@ -150,7 +150,7 @@ fuzz-build: vendor/sqlite3ext.h sqlite-predict.h
150150
-DSQLITE_CORE -DSQLITE_PREDICT_STATIC -DSQLITE_STRICT_SUBTYPE=1 \
151151
-Ivendor/ -I./ \
152152
fuzz/fuzz_predict.c $(OBJS) vendor/sqlite3.c \
153-
-o $(prefix)/fuzz_predict
153+
-o $(prefix)/fuzz_predict -lm -lpthread -ldl
154154

155155
fuzz: fuzz-build
156156
mkdir -p fuzz/corpus
@@ -194,14 +194,21 @@ soak-wasm: $(prefix) vendor/sqlite3ext.h sqlite-predict.h
194194
-sALLOW_MEMORY_GROWTH -sEXIT_RUNTIME=1 -sSTACK_SIZE=1048576 \
195195
tests/soak.c $(OBJS) vendor/sqlite3.c -o $(prefix)/soak.js
196196

197+
# refresh the gitignored dev copies of the loadable inside the language
198+
# bindings, so their local test suites exercise the current build
199+
bindings-dev: loadable
200+
cp $(prefix)/predict0.$(LOADABLE_EXTENSION) bindings/node/
201+
cp $(prefix)/predict0.$(LOADABLE_EXTENSION) bindings/python/sqlite_predict/
202+
197203
clean:
198204
rm -rf $(prefix) sqlite-predict.h
199205

200206
format:
201207
clang-format -i sqlite-predict.c predict-*.c
202208

203209
.PHONY: loadable loadable-onnx loadable-onnx-gpu amalgamation amalgamation-check python-src rust-src \
204-
sync-version debug test test-loadable test-onnx test-asan-onnx clean format
210+
sync-version debug test test-loadable test-onnx test-asan test-asan-onnx test-valgrind \
211+
fuzz fuzz-build fuzz-docker soak soak-wasm bindings-dev clean format
205212

206213
# stage the amalgamation + SQLite ext headers into the python package so it can
207214
# build a self-contained wheel (used by dev installs and the wheels workflow)

‎RELEASING.md‎

Lines changed: 51 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,74 @@
1-
# Releasing & claiming sqlite-predict
1+
# Releasing sqlite-predict
22

3-
Two separate jobs: **claim the names** (do this before any public mention, so
4-
nobody squats them) and **cut a release** (the functional launch). The generic
5-
`sqlite-predict` name is the one worth claiming everywhere; the everpure-scoped /
6-
prefixed packages are brand mirrors and lower urgency.
3+
Releases are tag-driven. Pushing a `v*` tag fires four workflows that
4+
build and publish everything; the manual part is syncing the version,
5+
committing, and tagging.
76

8-
Do everything under **org-owned accounts** (everpure / Pure Storage), never a
9-
personal login, so publishing survives people leaving.
10-
11-
---
12-
13-
## Part 1 — Claim the names now
14-
15-
Flat-namespace registries are first-come-first-served, so these three are the
16-
real squat risk. Each artifact below is already built and verified in this repo;
17-
you only need the account. Bump the version and re-run for later releases.
18-
19-
### PyPI — `sqlite-predict`
7+
## Cut a release
208

21-
1. Create a PyPI account, then an API token (Account settings -> API tokens).
22-
2. Build (or reuse the built) sdist and upload:
9+
1. Sync every manifest to the new version:
2310

2411
```sh
25-
make python-src
26-
python -m build --sdist --outdir bindings/python/dist bindings/python
27-
python -m twine upload -u __token__ -p pypi-XXXX \
28-
bindings/python/dist/sqlite_predict-*.tar.gz
12+
make sync-version V=0.0.2
2913
```
3014

31-
The sdist claims the name and is installable (it compiles on the user's
32-
machine). Compiler-free **wheels** come from the tag pipeline in Part 2.
15+
This writes `VERSION` and syncs it into `bindings/rust/Cargo.toml`,
16+
`bindings/python/pyproject.toml` (PEP 440 form, e.g. `0.0.1-alpha.5`
17+
becomes `0.0.1a5`), `bindings/python/sqlite_predict/__init__.py`
18+
(`__version__`), and `bindings/node/package.json` (including the
19+
per-platform `optionalDependencies` pins). The C header derives its
20+
version from `VERSION` at build time and needs no edit.
3321

34-
### crates.io — `sqlite-predict`
22+
2. Commit the version bump.
3523

36-
1. Log in to crates.io with the org GitHub account; create an API token.
37-
2. Publish (the crate compiles the amalgamation itself; fully functional on
38-
install):
24+
3. Tag and push:
3925

4026
```sh
41-
cargo login <token>
42-
make rust-src
43-
cargo publish --manifest-path bindings/rust/Cargo.toml --allow-dirty
27+
git tag v0.0.2
28+
git push && git push --tags
4429
```
4530

46-
`--allow-dirty` is needed because `csrc/` is generated (git-ignored); it is
47-
still included in the published crate via `Cargo.toml`'s `include`.
48-
49-
### npm — `sqlite-predict` (unscoped)
50-
51-
1. `npm login` as the org account.
52-
2. Publish the main package to claim the name:
53-
54-
```sh
55-
cd bindings/node && npm publish --access public
56-
```
31+
That is the whole procedure. Registry versions (PyPI, crates.io, npm)
32+
are immutable: if a publish job fails partway, fix the cause and cut a
33+
fresh version rather than re-tagging.
5734

58-
NOTE: this **claims the name but is not yet functional.** The package resolves
59-
its binary from per-platform packages (`sqlite-predict-<platform>`) that must
60-
be built and published by CI (not wired yet — see "Open follow-ups"). Claim
61-
now; make it functional before you announce npm.
35+
## What the tag triggers
6236

63-
### GitHub Releases — no account
37+
All four workflows in `.github/workflows/` fire on every `v*` tag push:
6438

65-
Nothing to claim; the repo owns it. See Part 2.
39+
| Workflow | Publishes | Credentials |
40+
| --- | --- | --- |
41+
| `release.yml` | GitHub Release: prebuilt loadables for Linux, macOS, and Windows, the single-file amalgamation (`sqlite-predict.c`), and `SHA256SUMS`, with generated release notes | built-in `GITHUB_TOKEN` |
42+
| `wheels.yml` | Python wheels (manylinux and macOS, compiler-free `pip install sqlite-predict`) plus the sdist, to PyPI | trusted publishing (OIDC), no stored token |
43+
| `npm.yml` | the per-platform binary packages (`sqlite-predict-darwin-arm64`, `sqlite-predict-darwin-x64`, `sqlite-predict-linux-x64`, `sqlite-predict-linux-arm64`, `sqlite-predict-windows-x64`), then the main `sqlite-predict` package with `optionalDependencies` pinned to the same version | `NPM_TOKEN` repo secret |
44+
| `crate.yml` | the `sqlite-predict` crate to crates.io (the crate's `build.rs` compiles the bundled amalgamation on the user's machine) | `CARGO_REGISTRY_TOKEN` repo secret |
6645

67-
---
46+
`npm.yml` and `crate.yml` also support `workflow_dispatch` with an
47+
explicit version input, for re-running a single registry publish
48+
without a new tag.
6849

69-
## Part 2 — Cut a release
50+
## One-time setup (already done, recorded for repo moves)
7051

71-
Tagging drives everything else automatically (built-in `GITHUB_TOKEN`, no
72-
external secrets for the binaries):
52+
- **PyPI trusted publisher** on the `sqlite-predict` project: owner
53+
`PureStorage-OpenConnect`, repository `sqlite-predict`, workflow
54+
`wheels.yml`, environment `pypi`. A matching `pypi` GitHub
55+
environment must exist (Settings, then Environments). If the repo
56+
moves, update the trusted publisher's owner.
57+
- **`NPM_TOKEN`**: an npm automation token for the org account, stored
58+
as a repo secret.
59+
- **`CARGO_REGISTRY_TOKEN`**: a crates.io API token for the org
60+
account, stored as a repo secret.
7361

74-
```sh
75-
git tag v0.0.1-alpha.1
76-
git push origin v0.0.1-alpha.1
77-
```
78-
79-
- `release.yml` builds Linux/macOS/Windows loadables + the amalgamation
80-
(`sqlite-predict.c`) + `SHA256SUMS` and publishes a GitHub Release.
81-
- `wheels.yml` builds the Python wheels + sdist and, once PyPI trusted
82-
publishing is configured (below), uploads them so `pip install sqlite-predict`
83-
is compiler-free.
84-
85-
### PyPI trusted publishing (one-time, recommended over tokens)
86-
87-
On PyPI -> the `sqlite-predict` project -> Publishing -> add a trusted publisher:
88-
89-
| field | value |
90-
| --- | --- |
91-
| Owner | `PureStorage-OpenConnect` (or the everpure org, if the repo moves) |
92-
| Repository | `sqlite-predict` |
93-
| Workflow | `wheels.yml` |
94-
| Environment | `pypi` |
95-
96-
Then create a `pypi` GitHub environment (Settings -> Environments). After that,
97-
a `v*` tag publishes wheels with no token stored in GitHub.
98-
99-
---
100-
101-
## Part 3 — Brand mirrors (everpure)
102-
103-
Lower urgency: `@everpure/*` on npm is already yours by scope, and the prefixed
104-
PyPI/crates names aren't the discoverable target. When ready, publish the same
105-
content under the branded names (`everpure-sqlite-predict` on PyPI/crates,
106-
`@everpure/sqlite-predict` on npm) as thin mirror packages. Ask and this can be
107-
wired into the release workflows.
62+
All registry accounts are org-owned (everpure / Pure Storage), never a
63+
personal login, so publishing survives people leaving.
10864

109-
---
65+
## Names claimed as of alpha.5
11066

111-
## Open follow-ups (not blocking the name claims)
67+
The generic `sqlite-predict` name is claimed and functional on all
68+
three flat-namespace registries: PyPI, crates.io, and npm (the main
69+
package plus the five per-platform binary packages listed above).
70+
GitHub Releases need no claim; the repo owns them.
11271

113-
- **npm per-platform binary packages** + a workflow to build/publish them, so
114-
`npm install sqlite-predict` ships a working binary (today only the name is
115-
claimable). Same pattern as the wheels.
116-
- **Windows/musl/arm wheel coverage** in `wheels.yml` (currently CPython
117-
manylinux + macOS).
118-
- The brand mirror packages in Part 3.
72+
The everpure-branded mirror names (`everpure-sqlite-predict` on PyPI
73+
and crates.io, `@everpure/sqlite-predict` on npm) are unclaimed and low
74+
urgency; the npm scope already belongs to the org.

‎SECURITY.md‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Security Policy
1+
# Security policy
22

33
## Reporting a vulnerability
44

@@ -39,7 +39,6 @@ particular attention:
3939
forecast horizons, and per-call work are bounded, and interrupts are
4040
honored between batches.
4141

42-
Error messages do not echo input row values. Receipts are as sensitive as
43-
the queries they record.
42+
Error messages do not echo input row values.
4443

4544
[ghsa]: https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability
File renamed without changes.

‎fuzz/seeds/README‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
aggopts1 and opts1 deliberately keep the removed "receipt":0 key: unknown option keys are fuzz fodder for the fail-loud options-rejection path.

0 commit comments

Comments
 (0)