From f7c1bd79b0d6fd75057ff8e7642008edb27a5ff9 Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Sat, 10 Oct 2026 22:01:13 +0000 Subject: [PATCH] =?UTF-8?q?fuzz-target-every-parse:=20the=20=C2=A73.2=20di?= =?UTF-8?q?fferential=20target=20=E2=80=94=20three=20parsers=20+=20skip=5F?= =?UTF-8?q?forward=20through=20the=20doc-hidden=20surfaces=20via=20shared?= =?UTF-8?q?=20invariants,=2066=20committed=20seeds=20+=20gitignore=20negat?= =?UTF-8?q?ion=20+=20README=20row;=20two=20real=20skip=5Fforward=20finding?= =?UTF-8?q?s=20fixed=20inline=20(division-by-zero/negative-interval=20wrap?= =?UTF-8?q?=20on=20sqlite+mem,=20i64=20gap=20subtraction=20overflow=20on?= =?UTF-8?q?=20all=20three=20engines=20incl.=20pg)=20and=20registered=20as?= =?UTF-8?q?=20PROVENANCE=20D-38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- alkstore-mem/src/scheduler.rs | 4 +- alkstore-postgres/src/scheduler.rs | 2 +- alkstore-sqlite/src/substrate/PROVENANCE.md | 1 + alkstore-sqlite/src/substrate/queue_ops.rs | 4 +- fuzz/.gitignore | 1 + fuzz/Cargo.lock | 958 +++++++++++++++++++- fuzz/Cargo.toml | 7 + fuzz/README.md | 2 +- fuzz/corpus/every_parse/seed-000 | 1 + fuzz/corpus/every_parse/seed-001 | 1 + fuzz/corpus/every_parse/seed-002 | 1 + fuzz/corpus/every_parse/seed-003 | 1 + fuzz/corpus/every_parse/seed-004 | 1 + fuzz/corpus/every_parse/seed-005 | 1 + fuzz/corpus/every_parse/seed-006 | 1 + fuzz/corpus/every_parse/seed-007 | 1 + fuzz/corpus/every_parse/seed-008 | 1 + fuzz/corpus/every_parse/seed-009 | 1 + fuzz/corpus/every_parse/seed-010 | 1 + fuzz/corpus/every_parse/seed-011 | 1 + fuzz/corpus/every_parse/seed-012 | 1 + fuzz/corpus/every_parse/seed-013 | 1 + fuzz/corpus/every_parse/seed-014 | 1 + fuzz/corpus/every_parse/seed-015 | 1 + fuzz/corpus/every_parse/seed-016 | 1 + fuzz/corpus/every_parse/seed-017 | 1 + fuzz/corpus/every_parse/seed-018 | 1 + fuzz/corpus/every_parse/seed-019 | 1 + fuzz/corpus/every_parse/seed-020 | 1 + fuzz/corpus/every_parse/seed-021 | 1 + fuzz/corpus/every_parse/seed-022 | 1 + fuzz/corpus/every_parse/seed-023 | 1 + fuzz/corpus/every_parse/seed-024 | 1 + fuzz/corpus/every_parse/seed-025 | 1 + fuzz/corpus/every_parse/seed-026 | 1 + fuzz/corpus/every_parse/seed-027 | 1 + fuzz/corpus/every_parse/seed-028 | 1 + fuzz/corpus/every_parse/seed-029 | 1 + fuzz/corpus/every_parse/seed-030 | 1 + fuzz/corpus/every_parse/seed-031 | 1 + fuzz/corpus/every_parse/seed-032 | 1 + fuzz/corpus/every_parse/seed-033 | 1 + fuzz/corpus/every_parse/seed-034 | 1 + fuzz/corpus/every_parse/seed-035 | 1 + fuzz/corpus/every_parse/seed-036 | 1 + fuzz/corpus/every_parse/seed-037 | 1 + fuzz/corpus/every_parse/seed-038 | 1 + fuzz/corpus/every_parse/seed-039 | 1 + fuzz/corpus/every_parse/seed-040 | 1 + fuzz/corpus/every_parse/seed-041 | 1 + fuzz/corpus/every_parse/seed-042 | 1 + fuzz/corpus/every_parse/seed-043 | 1 + fuzz/corpus/every_parse/seed-044 | 1 + fuzz/corpus/every_parse/seed-045 | 1 + fuzz/corpus/every_parse/seed-046 | 1 + fuzz/corpus/every_parse/seed-047 | 1 + fuzz/corpus/every_parse/seed-048 | 1 + fuzz/corpus/every_parse/seed-049 | 1 + fuzz/corpus/every_parse/seed-050 | 1 + fuzz/corpus/every_parse/seed-051 | 1 + fuzz/corpus/every_parse/seed-052 | 1 + fuzz/corpus/every_parse/seed-053 | 1 + fuzz/corpus/every_parse/seed-054 | 1 + fuzz/corpus/every_parse/seed-055 | 1 + fuzz/corpus/every_parse/seed-056 | 1 + fuzz/corpus/every_parse/seed-057 | 1 + fuzz/corpus/every_parse/seed-058 | 1 + fuzz/corpus/every_parse/seed-059 | 1 + fuzz/corpus/every_parse/seed-060 | 1 + fuzz/corpus/every_parse/seed-061 | 1 + fuzz/corpus/every_parse/seed-062 | Bin 0 -> 24 bytes fuzz/corpus/every_parse/seed-063 | 1 + fuzz/corpus/every_parse/seed-064 | Bin 0 -> 24 bytes fuzz/corpus/every_parse/seed-065 | Bin 0 -> 24 bytes fuzz/fuzz_targets/every_parse.rs | 11 + fuzz/gen_fuzz_seeds.py | 122 +++ fuzz/shared/Cargo.toml | 3 + fuzz/shared/src/every_parse.rs | 276 ++++++ fuzz/shared/src/lib.rs | 1 + tasks/fuzz-target-every-parse.md | 122 ++- 80 files changed, 1559 insertions(+), 18 deletions(-) create mode 100644 fuzz/corpus/every_parse/seed-000 create mode 100644 fuzz/corpus/every_parse/seed-001 create mode 100644 fuzz/corpus/every_parse/seed-002 create mode 100644 fuzz/corpus/every_parse/seed-003 create mode 100644 fuzz/corpus/every_parse/seed-004 create mode 100644 fuzz/corpus/every_parse/seed-005 create mode 100644 fuzz/corpus/every_parse/seed-006 create mode 100644 fuzz/corpus/every_parse/seed-007 create mode 100644 fuzz/corpus/every_parse/seed-008 create mode 100644 fuzz/corpus/every_parse/seed-009 create mode 100644 fuzz/corpus/every_parse/seed-010 create mode 100644 fuzz/corpus/every_parse/seed-011 create mode 100644 fuzz/corpus/every_parse/seed-012 create mode 100644 fuzz/corpus/every_parse/seed-013 create mode 100644 fuzz/corpus/every_parse/seed-014 create mode 100644 fuzz/corpus/every_parse/seed-015 create mode 100644 fuzz/corpus/every_parse/seed-016 create mode 100644 fuzz/corpus/every_parse/seed-017 create mode 100644 fuzz/corpus/every_parse/seed-018 create mode 100644 fuzz/corpus/every_parse/seed-019 create mode 100644 fuzz/corpus/every_parse/seed-020 create mode 100644 fuzz/corpus/every_parse/seed-021 create mode 100644 fuzz/corpus/every_parse/seed-022 create mode 100644 fuzz/corpus/every_parse/seed-023 create mode 100644 fuzz/corpus/every_parse/seed-024 create mode 100644 fuzz/corpus/every_parse/seed-025 create mode 100644 fuzz/corpus/every_parse/seed-026 create mode 100644 fuzz/corpus/every_parse/seed-027 create mode 100644 fuzz/corpus/every_parse/seed-028 create mode 100644 fuzz/corpus/every_parse/seed-029 create mode 100644 fuzz/corpus/every_parse/seed-030 create mode 100644 fuzz/corpus/every_parse/seed-031 create mode 100644 fuzz/corpus/every_parse/seed-032 create mode 100644 fuzz/corpus/every_parse/seed-033 create mode 100644 fuzz/corpus/every_parse/seed-034 create mode 100644 fuzz/corpus/every_parse/seed-035 create mode 100644 fuzz/corpus/every_parse/seed-036 create mode 100644 fuzz/corpus/every_parse/seed-037 create mode 100644 fuzz/corpus/every_parse/seed-038 create mode 100644 fuzz/corpus/every_parse/seed-039 create mode 100644 fuzz/corpus/every_parse/seed-040 create mode 100644 fuzz/corpus/every_parse/seed-041 create mode 100644 fuzz/corpus/every_parse/seed-042 create mode 100644 fuzz/corpus/every_parse/seed-043 create mode 100644 fuzz/corpus/every_parse/seed-044 create mode 100644 fuzz/corpus/every_parse/seed-045 create mode 100644 fuzz/corpus/every_parse/seed-046 create mode 100644 fuzz/corpus/every_parse/seed-047 create mode 100644 fuzz/corpus/every_parse/seed-048 create mode 100644 fuzz/corpus/every_parse/seed-049 create mode 100644 fuzz/corpus/every_parse/seed-050 create mode 100644 fuzz/corpus/every_parse/seed-051 create mode 100644 fuzz/corpus/every_parse/seed-052 create mode 100644 fuzz/corpus/every_parse/seed-053 create mode 100644 fuzz/corpus/every_parse/seed-054 create mode 100644 fuzz/corpus/every_parse/seed-055 create mode 100644 fuzz/corpus/every_parse/seed-056 create mode 100644 fuzz/corpus/every_parse/seed-057 create mode 100644 fuzz/corpus/every_parse/seed-058 create mode 100644 fuzz/corpus/every_parse/seed-059 create mode 100644 fuzz/corpus/every_parse/seed-060 create mode 100644 fuzz/corpus/every_parse/seed-061 create mode 100644 fuzz/corpus/every_parse/seed-062 create mode 100644 fuzz/corpus/every_parse/seed-063 create mode 100644 fuzz/corpus/every_parse/seed-064 create mode 100644 fuzz/corpus/every_parse/seed-065 create mode 100644 fuzz/fuzz_targets/every_parse.rs create mode 100644 fuzz/shared/src/every_parse.rs diff --git a/alkstore-mem/src/scheduler.rs b/alkstore-mem/src/scheduler.rs index c74ffa9..3b02425 100644 --- a/alkstore-mem/src/scheduler.rs +++ b/alkstore-mem/src/scheduler.rs @@ -252,8 +252,8 @@ fn fire_due(sched: &mut ScheduleState, queues: &mut QueueState, state: &State, n /// in the future, grid-aligned (the schedule row's advance makes the /// gap inspectable). pub fn skip_forward(next_fire_at: i64, now: i64, interval: i64) -> i64 { - let gap = (now - next_fire_at) as i128; - let interval = interval as i128; + let gap = now as i128 - next_fire_at as i128; + let interval = interval.max(1) as i128; let next = (next_fire_at as i128) + (gap / interval + 1) * interval; if next > i64::MAX as i128 { i64::MAX diff --git a/alkstore-postgres/src/scheduler.rs b/alkstore-postgres/src/scheduler.rs index 382375f..0760dad 100644 --- a/alkstore-postgres/src/scheduler.rs +++ b/alkstore-postgres/src/scheduler.rs @@ -262,7 +262,7 @@ fn next_every_boundary(spec: &str, after: i64) -> Result { /// (the skipped boundaries never enqueue). 128-bit intermediates keep /// the arithmetic saturation-safe; the result clamps at `i64::MAX`. pub fn skip_forward(next_fire_at: i64, now: i64, interval: i64) -> i64 { - let gap = (now - next_fire_at) as i128; + let gap = now as i128 - next_fire_at as i128; let interval = interval.max(1) as i128; let next = (next_fire_at as i128) + (gap / interval + 1) * interval; if next > i64::MAX as i128 { diff --git a/alkstore-sqlite/src/substrate/PROVENANCE.md b/alkstore-sqlite/src/substrate/PROVENANCE.md index c1db409..1d641e0 100644 --- a/alkstore-sqlite/src/substrate/PROVENANCE.md +++ b/alkstore-sqlite/src/substrate/PROVENANCE.md @@ -130,6 +130,7 @@ Cherry-picks: empty at scaffold, append-only forever. | D-35 | drop | `Writer::try_acquire` cut (the non-blocking writer-slot try): upstream's embedding harness used it for try-shaped entry points its surface exposed; this engine's seam always blocks (`acquire`) — the writer-slot lease is a *parks-the-writer* lease by design (ADR-007's honest model), so a try-shaped acquire would contradict the posture rather than extend it. The probe tests driving it re-express their properties through `acquire`/`release`/`close` (the engine-reachable surface); the engine-level lease tests (`tx_tests`' lease/parking suite) pin the observable posture end-to-end | `schema.rs` (`Writer::try_acquire` + the three `writer_reader_tests` call sites) | ADR-007 (the caller-held-lease seam: `begin_tx` parks a concurrent writer — no try-shaped begin exists on the contract surface); ADR-012 §2 (nothing on the engine side reaches a try-acquire); wave-3 lint-removal obligation — cut, not suppressed | ours | | D-36 | drop | `UpdateWatcher::spawn` and `SharedUpdateWatcher::new` cut (the default-cadence convenience constructors): upstream's embedding harnesses opened watchers without explicit config; this engine's single open path always constructs a `WatcherConfig` — from `SqliteOpts` (ADR-023 §4's `poll_interval` knob, `None` = the 1 ms default) — and passes it through `*_with_config`; a config-less twin would re-create two open postures (the mixed-flag inconsistency D-29 resolved at the URI layer). `WatcherConfig::default()` remains the default's single owner; the tests driving the cut constructors now build the config explicitly, pinning the same behavior | `watcher.rs` (both constructors + five watcher-test call sites) | ADR-023 §4 (the cadence knob rides the engine's opts — one open posture carries config); ADR-012 §2 (one construction path the engine reviews); wave-3 lint-removal obligation — cut, not suppressed | ours | | D-37 | re-derivation | visibility-only widening on the re-derived `@every` surface: `parse_every_interval` (`pub(crate)` → `pub`) and `skip_forward` (module-private → `pub`) in `queue_ops.rs`, plus this subtree's facade re-export (`mod.rs`: `pub use queue_ops::{parse_every_interval, skip_forward}`), so the engine crate root can `#[doc(hidden)] pub use` both as the wave-7 fuzzing differential target's drive surface (`fuzz-parser-exposure`, target `every_parse`). Zero logic change, zero signature change, zero name change; `mod substrate` stays private, so containment holds — nothing leaves the crate except the doc-hidden root re-exports. A `pub use` re-export mechanically requires item-level `pub` (E0364/E0603), which is why the facade line is in `mod.rs`; the module doc's "nothing re-exported" boundary sentence was amended in the same commit to name this sole exception | `queue_ops.rs` (two visibility keywords); `mod.rs` (facade re-export line + boundary-doc exception sentence) | ADR-012 §3 (fidelity governs the ported honker body — `watcher.rs`/`schema.rs`/`ops.rs` untouched; `queue_ops.rs` is the re-derived half, owned contract-v1 code, so a visibility-only delta is legitimate); docs/research/fuzzing.md §3.2 (option (b): the `#[doc(hidden)]` narrow exposure); ADR-017 §3 (doc-hidden test surface, no stability guarantee — the `Job::from_row` precedent) | ours | +| D-38 | port delta | degenerate/adversarial-triple hardening on `skip_forward` (two legs, both aligning to the pg engine's committed clamp shape where it existed and extending pg itself): (1) the `interval` is clamped (`interval.max(1) as i128`) — pre-fix, `interval == 0` panicked on i128 division-by-zero, reachable only through degenerate/non-grammar callers (the parsers reject `n <= 0`, so every engine-internal call site passes `interval >= 1`); (2) the gap is computed in i128 (`now as i128 - next_fire_at as i128`) — pre-fix, `now - next_fire_at` was an **i64 subtraction** that panics in debug (overflow) / silently wraps in release when `(next_fire_at, now)` straddle the full domain (`now=i64::MIN`-adjacent, `next_fire_at=i64::MAX`-adjacent), feeding a wrapped gap to the 128-bit arithmetic and breaking the saturation guarantee. Found by the `every_parse` differential target (wave 7, tasks/fuzz-target-every-parse) driving the adversarial `(next_fire_at, now, interval)` space; pg needed leg (2) as well. Observable behavior unaffected in the reachable domain (|gap| < i64 range), saturation posture now holds over the whole domain. Zero signature change; lineage body untouched (`skip_forward` is the re-derived scheduler half, D-12's own) | `queue_ops.rs` (`skip_forward`, two lines) | docs/research/fuzzing.md §3.2 (the overflow-posture invariant: reject-or-saturate, never wrap or panic, over the whole domain); wave-6's register-overflow alignment (tasks/review-wave-6); alkstore-postgres/src/scheduler.rs `skip_forward` (the pinned clamp shape) | ours | ### Cherry-picks diff --git a/alkstore-sqlite/src/substrate/queue_ops.rs b/alkstore-sqlite/src/substrate/queue_ops.rs index 687c733..3768199 100644 --- a/alkstore-sqlite/src/substrate/queue_ops.rs +++ b/alkstore-sqlite/src/substrate/queue_ops.rs @@ -525,8 +525,8 @@ fn next_every_boundary(spec: &str, after: i64) -> Result { } pub fn skip_forward(next_fire_at: i64, now: i64, interval: i64) -> i64 { - let gap = (now - next_fire_at) as i128; - let interval = interval as i128; + let gap = now as i128 - next_fire_at as i128; + let interval = interval.max(1) as i128; let next = (next_fire_at as i128) + (gap / interval + 1) * interval; if next > i64::MAX as i128 { i64::MAX diff --git a/fuzz/.gitignore b/fuzz/.gitignore index 40b96c7..e897774 100644 --- a/fuzz/.gitignore +++ b/fuzz/.gitignore @@ -1,5 +1,6 @@ target corpus/* !corpus/payload_codec +!corpus/every_parse artifacts coverage diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 3366e02..567ab1d 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -25,11 +25,48 @@ name = "alkstore-fuzz-shared" version = "0.0.0" dependencies = [ "alkstore", + "alkstore-mem", + "alkstore-postgres", + "alkstore-sqlite", "arbitrary", "serde", "serde_json", ] +[[package]] +name = "alkstore-mem" +version = "0.1.0" +dependencies = [ + "alkstore", + "serde_json", + "tokio", +] + +[[package]] +name = "alkstore-postgres" +version = "0.1.0" +dependencies = [ + "alkstore", + "deadpool-postgres", + "serde_json", + "thiserror", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "alkstore-sqlite" +version = "0.1.0" +dependencies = [ + "alkstore", + "file-id", + "parking_lot", + "rusqlite", + "serde_json", + "thiserror", + "tokio", +] + [[package]] name = "arbitrary" version = "1.5.0" @@ -39,6 +76,56 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.7", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + [[package]] name = "cc" version = "1.7.0" @@ -57,6 +144,89 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574" +dependencies = [ + "cmov", +] + +[[package]] +name = "deadpool" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e98a7e119cd347f4201e1159b19831029e203e2d8b790547708e8157b4acf1e" +dependencies = [ + "deadpool-runtime", + "tokio", +] + +[[package]] +name = "deadpool-postgres" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65a536565624b97fc19f758cd01b15d12908d3344425066efc8162236fbd3749" +dependencies = [ + "async-trait", + "deadpool", + "getrandom", + "tokio", + "tokio-postgres", + "tracing", +] + +[[package]] +name = "deadpool-runtime" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2657f61fb1dd8bf37a8d51093cc7cee4e77125b22f7753f49b289f831bec2bae" +dependencies = [ + "tokio", +] + [[package]] name = "derive_arbitrary" version = "1.5.0" @@ -65,7 +235,46 @@ checksum = "1b034bd7d5f032402a2479444dcc6f74e36a03f31854d41680fb240ef682a1ac" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "ctutils", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "file-id" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc6a637b6dc58414714eddd9170ff187ecb0933d4c7024d1abbd23a3cc26e9" +dependencies = [ + "windows-sys 0.60.2", ] [[package]] @@ -74,6 +283,53 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "slab", +] + [[package]] name = "getrandom" version = "0.4.3" @@ -81,8 +337,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", + "rand_core", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a596f1b20ed2cc5ecac41a164aaebc7258057060f06c0cf7a2ba3991ee7990fb" +dependencies = [ + "hashbrown 0.17.1", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest", +] + +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", ] [[package]] @@ -101,6 +405,17 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.190" @@ -117,12 +432,181 @@ dependencies = [ "cc", ] +[[package]] +name = "libredox" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" +dependencies = [ + "libc", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d20bef17f513b9b3004532233187769cd072d790971f4e4da0e346eb6401e8" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" +[[package]] +name = "mio" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", +] + +[[package]] +name = "objc2-system-configuration" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" +dependencies = [ + "objc2-core-foundation", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_shared", + "serde", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "postgres-protocol" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08808e3c483c46e999108051c78334f473d5adb59d78bb80a1268c7e6aa6c514" +dependencies = [ + "base64", + "byteorder", + "bytes", + "fallible-iterator 0.2.0", + "hmac", + "md-5", + "memchr", + "rand", + "sha2", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "851ca9db4932932d69f3ea811b1abe63087a0f740a47692619dd40d4899b68be" +dependencies = [ + "bytes", + "fallible-iterator 0.2.0", + "postgres-protocol", +] + [[package]] name = "proc-macro2" version = "1.0.107" @@ -147,6 +631,69 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rsqlite-vfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51c9ae4df8a7fba42103df5c621fa3c37eccf3a3c650879e90fc48b11cc192c" +dependencies = [ + "hashbrown 0.16.1", + "thiserror", +] + +[[package]] +name = "rusqlite" +version = "0.40.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f2a97da3e3873c73cb2a2e71b35c40ff95e0b1eefa8d72d8499a6928c3b5b3" +dependencies = [ + "bitflags", + "fallible-iterator 0.3.0", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", + "sqlite-wasm-rs", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "serde" version = "1.0.229" @@ -174,7 +721,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.7", ] [[package]] @@ -190,12 +737,85 @@ dependencies = [ "zmij", ] +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" +[[package]] +name = "siphasher" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b" + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3efc0da82635d7e1ced0053bbbfa8c7ab9645d0bf36ceb4f7127bb85315d75" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", + "wasm-bindgen", +] + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "3.0.7" @@ -224,15 +844,347 @@ checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.7", ] +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "tokio" +version = "1.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.7", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a528f7d280f6d5b9cd149635c8705b0dd049754bc67d81d31fa25169a93809d3" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator 0.2.0", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + +[[package]] +name = "tokio-util" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" +dependencies = [ + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.7", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" +dependencies = [ + "libc", + "libredox", + "objc2-system-configuration", + "wasite", + "web-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "zmij" version = "1.0.23" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index d5f8ea7..bf177b0 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -21,4 +21,11 @@ test = false doc = false bench = false +[[bin]] +name = "every_parse" +path = "fuzz_targets/every_parse.rs" +test = false +doc = false +bench = false + [workspace] \ No newline at end of file diff --git a/fuzz/README.md b/fuzz/README.md index 170b46a..18888a3 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -28,7 +28,7 @@ libFuzzer targets for alkstore's parse/codec surfaces (see | Target | Drives | Invariants | |---|---|---| | `payload_codec` | `encode_payload` / `payload_as::` (`alkstore/src/payload.rs`) | no-panic on any byte sequence; every decode failure typed `Error::Codec`; deep nesting loud at serde_json's recursion limit; `Value` round-trip (serde_json canonicalization pinned); typed round-trip for a representative payload set | -| `every_parse` | the three `parse_every_interval` implementations (differential) | filled by its target task | +| `every_parse` | the three `parse_every_interval` implementations (differential, through the engines' `#[doc(hidden)]` re-exports) + each engine's `skip_forward` boundary arithmetic | no-panic on any UTF-8-lossy string (each parser, each boundary path); typed rejection (`Error::InvalidSpec` on pg/mem, the substrate's error under its mapping on SQLite); three-way agreement on the Ok/Err partition and the `Ok` interval value (error identity not pinned — the SQLite `Result` vs `InvalidSpec` asymmetry is known); overflow posture: `skip_forward` over adversarial `(next_fire_at, now, interval)` triples rejects-or-saturates, never wraps or panics; the `n <= 0` and giant-`n` arms (leading zeros, digit overflow at exactly `i64::MAX/86400`, positive-zero rejection) | | `name_validation` | `validate_name` / `validate_shared_name` / `validate_local_name` (`alkstore/src/validation.rs`) | filled by its target task | ## Commands diff --git a/fuzz/corpus/every_parse/seed-000 b/fuzz/corpus/every_parse/seed-000 new file mode 100644 index 0000000..dd8c4a5 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-000 @@ -0,0 +1 @@ +@every 1s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-001 b/fuzz/corpus/every_parse/seed-001 new file mode 100644 index 0000000..3fd4e6e --- /dev/null +++ b/fuzz/corpus/every_parse/seed-001 @@ -0,0 +1 @@ +@every 5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-002 b/fuzz/corpus/every_parse/seed-002 new file mode 100644 index 0000000..ff5994e --- /dev/null +++ b/fuzz/corpus/every_parse/seed-002 @@ -0,0 +1 @@ +@every 9s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-003 b/fuzz/corpus/every_parse/seed-003 new file mode 100644 index 0000000..3106368 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-003 @@ -0,0 +1 @@ +@every 17s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-004 b/fuzz/corpus/every_parse/seed-004 new file mode 100644 index 0000000..1c1644d --- /dev/null +++ b/fuzz/corpus/every_parse/seed-004 @@ -0,0 +1 @@ +@every 42m \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-005 b/fuzz/corpus/every_parse/seed-005 new file mode 100644 index 0000000..58c2264 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-005 @@ -0,0 +1 @@ +@every 1m \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-006 b/fuzz/corpus/every_parse/seed-006 new file mode 100644 index 0000000..7908872 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-006 @@ -0,0 +1 @@ +@every 90m \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-007 b/fuzz/corpus/every_parse/seed-007 new file mode 100644 index 0000000..8ba9f4f --- /dev/null +++ b/fuzz/corpus/every_parse/seed-007 @@ -0,0 +1 @@ +@every 2h \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-008 b/fuzz/corpus/every_parse/seed-008 new file mode 100644 index 0000000..b6a1287 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-008 @@ -0,0 +1 @@ +@every 24h \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-009 b/fuzz/corpus/every_parse/seed-009 new file mode 100644 index 0000000..bc7a203 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-009 @@ -0,0 +1 @@ +@every 1d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-010 b/fuzz/corpus/every_parse/seed-010 new file mode 100644 index 0000000..6424361 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-010 @@ -0,0 +1 @@ +@every 7d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-011 b/fuzz/corpus/every_parse/seed-011 new file mode 100644 index 0000000..98ee3b8 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-011 @@ -0,0 +1 @@ +@every 365d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-012 b/fuzz/corpus/every_parse/seed-012 new file mode 100644 index 0000000..c4e6b4f --- /dev/null +++ b/fuzz/corpus/every_parse/seed-012 @@ -0,0 +1 @@ +@every 007s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-013 b/fuzz/corpus/every_parse/seed-013 new file mode 100644 index 0000000..531e734 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-013 @@ -0,0 +1 @@ +@every 007m \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-014 b/fuzz/corpus/every_parse/seed-014 new file mode 100644 index 0000000..511150f --- /dev/null +++ b/fuzz/corpus/every_parse/seed-014 @@ -0,0 +1 @@ +@every 000000042h \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-015 b/fuzz/corpus/every_parse/seed-015 new file mode 100644 index 0000000..e655188 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-015 @@ -0,0 +1 @@ +@every 007d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-016 b/fuzz/corpus/every_parse/seed-016 new file mode 100644 index 0000000..9a90c84 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-016 @@ -0,0 +1 @@ +@every 0s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-017 b/fuzz/corpus/every_parse/seed-017 new file mode 100644 index 0000000..59754a9 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-017 @@ -0,0 +1 @@ +@every 00m \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-018 b/fuzz/corpus/every_parse/seed-018 new file mode 100644 index 0000000..ee5abaf --- /dev/null +++ b/fuzz/corpus/every_parse/seed-018 @@ -0,0 +1 @@ +@every 0000d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-019 b/fuzz/corpus/every_parse/seed-019 new file mode 100644 index 0000000..a037c9d --- /dev/null +++ b/fuzz/corpus/every_parse/seed-019 @@ -0,0 +1 @@ +@every -5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-020 b/fuzz/corpus/every_parse/seed-020 new file mode 100644 index 0000000..d793185 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-020 @@ -0,0 +1 @@ +@every -0s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-021 b/fuzz/corpus/every_parse/seed-021 new file mode 100644 index 0000000..be00ad5 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-021 @@ -0,0 +1 @@ +@every 9223372036854775807s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-022 b/fuzz/corpus/every_parse/seed-022 new file mode 100644 index 0000000..1e5f4a2 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-022 @@ -0,0 +1 @@ +@every 9223372036854775806s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-023 b/fuzz/corpus/every_parse/seed-023 new file mode 100644 index 0000000..fa5ac59 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-023 @@ -0,0 +1 @@ +@every 9223372036854775808s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-024 b/fuzz/corpus/every_parse/seed-024 new file mode 100644 index 0000000..698aa22 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-024 @@ -0,0 +1 @@ +@every 9223372036854775807m \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-025 b/fuzz/corpus/every_parse/seed-025 new file mode 100644 index 0000000..c811745 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-025 @@ -0,0 +1 @@ +@every 9223372036854775807h \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-026 b/fuzz/corpus/every_parse/seed-026 new file mode 100644 index 0000000..6609067 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-026 @@ -0,0 +1 @@ +@every 9223372036854775807d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-027 b/fuzz/corpus/every_parse/seed-027 new file mode 100644 index 0000000..38962a8 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-027 @@ -0,0 +1 @@ +@every 18446744073709551616s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-028 b/fuzz/corpus/every_parse/seed-028 new file mode 100644 index 0000000..0e46fc0 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-028 @@ -0,0 +1 @@ +@every 18446744073709551616000000m \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-029 b/fuzz/corpus/every_parse/seed-029 new file mode 100644 index 0000000..a5315cc --- /dev/null +++ b/fuzz/corpus/every_parse/seed-029 @@ -0,0 +1 @@ +@every 106751991167300d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-030 b/fuzz/corpus/every_parse/seed-030 new file mode 100644 index 0000000..21afd35 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-030 @@ -0,0 +1 @@ +@every 106751991167301d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-031 b/fuzz/corpus/every_parse/seed-031 new file mode 100644 index 0000000..0b87e76 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-031 @@ -0,0 +1 @@ +@every 106751991167299d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-032 b/fuzz/corpus/every_parse/seed-032 new file mode 100644 index 0000000..8a4e370 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-032 @@ -0,0 +1 @@ +@every 2147483647d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-033 b/fuzz/corpus/every_parse/seed-033 new file mode 100644 index 0000000..f19a8bc --- /dev/null +++ b/fuzz/corpus/every_parse/seed-033 @@ -0,0 +1 @@ +@every 4294967295d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-034 b/fuzz/corpus/every_parse/seed-034 new file mode 100644 index 0000000..ea3187d --- /dev/null +++ b/fuzz/corpus/every_parse/seed-034 @@ -0,0 +1 @@ +@every 100000000000d \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-035 b/fuzz/corpus/every_parse/seed-035 new file mode 100644 index 0000000..1d4eaa5 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-035 @@ -0,0 +1 @@ +@every \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-036 b/fuzz/corpus/every_parse/seed-036 new file mode 100644 index 0000000..9659578 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-036 @@ -0,0 +1 @@ +@every \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-037 b/fuzz/corpus/every_parse/seed-037 new file mode 100644 index 0000000..0d1c0ef --- /dev/null +++ b/fuzz/corpus/every_parse/seed-037 @@ -0,0 +1 @@ +@every 5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-038 b/fuzz/corpus/every_parse/seed-038 new file mode 100644 index 0000000..fa32da4 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-038 @@ -0,0 +1 @@ +@every 5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-039 b/fuzz/corpus/every_parse/seed-039 new file mode 100644 index 0000000..5e224d4 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-039 @@ -0,0 +1 @@ +@every 5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-040 b/fuzz/corpus/every_parse/seed-040 new file mode 100644 index 0000000..01c8644 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-040 @@ -0,0 +1 @@ +@every 5 s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-041 b/fuzz/corpus/every_parse/seed-041 new file mode 100644 index 0000000..ce3372a --- /dev/null +++ b/fuzz/corpus/every_parse/seed-041 @@ -0,0 +1 @@ +@every 5sx \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-042 b/fuzz/corpus/every_parse/seed-042 new file mode 100644 index 0000000..26c31aa --- /dev/null +++ b/fuzz/corpus/every_parse/seed-042 @@ -0,0 +1 @@ +@every 5S \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-043 b/fuzz/corpus/every_parse/seed-043 new file mode 100644 index 0000000..8a9a5b3 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-043 @@ -0,0 +1 @@ +@every +5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-044 b/fuzz/corpus/every_parse/seed-044 new file mode 100644 index 0000000..fbb7ae6 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-044 @@ -0,0 +1 @@ +@every .5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-045 b/fuzz/corpus/every_parse/seed-045 new file mode 100644 index 0000000..7a05a16 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-045 @@ -0,0 +1 @@ +@every 3.5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-046 b/fuzz/corpus/every_parse/seed-046 new file mode 100644 index 0000000..c47f511 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-046 @@ -0,0 +1 @@ +@every 5.0s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-047 b/fuzz/corpus/every_parse/seed-047 new file mode 100644 index 0000000..2b625fd --- /dev/null +++ b/fuzz/corpus/every_parse/seed-047 @@ -0,0 +1 @@ +@every 5 s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-048 b/fuzz/corpus/every_parse/seed-048 new file mode 100644 index 0000000..f678798 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-048 @@ -0,0 +1 @@ +@every és \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-049 b/fuzz/corpus/every_parse/seed-049 new file mode 100644 index 0000000..816a584 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-049 @@ -0,0 +1 @@ +ÿ @every ÿ 5s þ \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-050 b/fuzz/corpus/every_parse/seed-050 new file mode 100644 index 0000000..297b4fa --- /dev/null +++ b/fuzz/corpus/every_parse/seed-050 @@ -0,0 +1 @@ +@every 5sÿ \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-051 b/fuzz/corpus/every_parse/seed-051 new file mode 100644 index 0000000..f06d176 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-051 @@ -0,0 +1 @@ +@once \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-052 b/fuzz/corpus/every_parse/seed-052 new file mode 100644 index 0000000..6134d02 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-052 @@ -0,0 +1 @@ +@hourly \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-053 b/fuzz/corpus/every_parse/seed-053 new file mode 100644 index 0000000..66957b4 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-053 @@ -0,0 +1 @@ +@daily \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-054 b/fuzz/corpus/every_parse/seed-054 new file mode 100644 index 0000000..6c29f6e --- /dev/null +++ b/fuzz/corpus/every_parse/seed-054 @@ -0,0 +1 @@ +@weekly \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-055 b/fuzz/corpus/every_parse/seed-055 new file mode 100644 index 0000000..410a87c --- /dev/null +++ b/fuzz/corpus/every_parse/seed-055 @@ -0,0 +1 @@ +*/5 * * * * \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-056 b/fuzz/corpus/every_parse/seed-056 new file mode 100644 index 0000000..9ae0998 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-056 @@ -0,0 +1 @@ +0 0 * * * \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-057 b/fuzz/corpus/every_parse/seed-057 new file mode 100644 index 0000000..89c1315 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-057 @@ -0,0 +1 @@ +every 5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-058 b/fuzz/corpus/every_parse/seed-058 new file mode 100644 index 0000000..bf26a94 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-058 @@ -0,0 +1 @@ +5s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-059 b/fuzz/corpus/every_parse/seed-059 new file mode 100644 index 0000000..1b3ee9e --- /dev/null +++ b/fuzz/corpus/every_parse/seed-059 @@ -0,0 +1 @@ +@every 5 \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-060 b/fuzz/corpus/every_parse/seed-060 new file mode 100644 index 0000000..d77d7ec --- /dev/null +++ b/fuzz/corpus/every_parse/seed-060 @@ -0,0 +1 @@ +@every s \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-061 b/fuzz/corpus/every_parse/seed-061 new file mode 100644 index 0000000..01ec00a --- /dev/null +++ b/fuzz/corpus/every_parse/seed-061 @@ -0,0 +1 @@ +@every 9223372036854775807s skip-forward-triple payload XXXXX \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-062 b/fuzz/corpus/every_parse/seed-062 new file mode 100644 index 0000000000000000000000000000000000000000..4ac5fc6cf890b46738523c4d4d9d964e312f368f GIT binary patch literal 24 KcmZQzzzzTa7ytnP literal 0 HcmV?d00001 diff --git a/fuzz/corpus/every_parse/seed-063 b/fuzz/corpus/every_parse/seed-063 new file mode 100644 index 0000000..ccacfe1 --- /dev/null +++ b/fuzz/corpus/every_parse/seed-063 @@ -0,0 +1 @@ +ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file diff --git a/fuzz/corpus/every_parse/seed-064 b/fuzz/corpus/every_parse/seed-064 new file mode 100644 index 0000000000000000000000000000000000000000..9eb4b4a0b6e0704f913c98394ff80e80048c9cf5 GIT binary patch literal 24 UcmezW9}MalAi$yF1T&Zg0H(eP1ONa4 literal 0 HcmV?d00001 diff --git a/fuzz/corpus/every_parse/seed-065 b/fuzz/corpus/every_parse/seed-065 new file mode 100644 index 0000000000000000000000000000000000000000..9ec90d46f918c51b87676c92362d7f783a266e8d GIT binary patch literal 24 UcmZQ%0E34A5K!MR=?|C%0ED9t0{{R3 literal 0 HcmV?d00001 diff --git a/fuzz/fuzz_targets/every_parse.rs b/fuzz/fuzz_targets/every_parse.rs new file mode 100644 index 0000000..4395696 --- /dev/null +++ b/fuzz/fuzz_targets/every_parse.rs @@ -0,0 +1,11 @@ +//! The §3.2 target: the three per-engine `@every` parsers driven +//! differentially through the `fuzz-parser-exposure` doc-hidden +//! surfaces, plus each engine's `skip_forward` boundary arithmetic. + +#![no_main] + +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|data: &[u8]| { + alkstore_fuzz_shared::every_parse::fuzz_every_parse(data); +}); \ No newline at end of file diff --git a/fuzz/gen_fuzz_seeds.py b/fuzz/gen_fuzz_seeds.py index a8adba1..56880b7 100644 --- a/fuzz/gen_fuzz_seeds.py +++ b/fuzz/gen_fuzz_seeds.py @@ -124,8 +124,130 @@ def payload_codec_seeds(): i += 1 +def every_parse_seeds(): + i = 0 + + # Every grammar-valid unit form (s|m|h|d), single and multi-digit. + for spec in [ + "@every 1s", + "@every 5s", + "@every 9s", + "@every 17s", + "@every 42m", + "@every 1m", + "@every 90m", + "@every 2h", + "@every 24h", + "@every 1d", + "@every 7d", + "@every 365d", + ]: + write_seed("every_parse", i, spec.encode()) + i += 1 + + # Leading-zero forms (parsed through, value = the digits). + for spec in ["@every 007s", "@every 007m", "@every 000000042h", "@every 007d"]: + write_seed("every_parse", i, spec.encode()) + i += 1 + + # The n <= 0 arms: positive zero (with and without leading zeros) + # and the negative shapes (digits == 0 inside the grammar). + for spec in ["@every 0s", "@every 00m", "@every 0000d", "@every -5s", "@every -0s"]: + write_seed("every_parse", i, spec.encode()) + i += 1 + + # The i64::MAX neighborhood: giant-n accept at scale-1, digit + # overflow past i64, and unit-multiplier overflow above it. + for spec in [ + "@every 9223372036854775807s", + "@every 9223372036854775806s", + "@every 9223372036854775808s", + "@every 9223372036854775807m", + "@every 9223372036854775807h", + "@every 9223372036854775807d", + "@every 18446744073709551616s", + "@every 18446744073709551616000000m", + ]: + write_seed("every_parse", i, spec.encode()) + i += 1 + + # The digit-overflow boundary at exactly i64::MAX/86400 (and ±1). + for spec in [ + "@every 106751991167300d", + "@every 106751991167301d", + "@every 106751991167299d", + ]: + write_seed("every_parse", i, spec.encode()) + i += 1 + + # d-unit multiplier blowups. + for spec in ["@every 2147483647d", "@every 4294967295d", "@every 100000000000d"]: + write_seed("every_parse", i, spec.encode()) + i += 1 + + # Whitespace / garbage / truncation shapes. + for raw in [ + b"@every", + b"@every ", + b"@every 5s", + b"@every 5s ", + b"@every\t5s", + b"@every 5 s", + b"@every 5sx", + b"@every 5S", + b"@every +5s", + b"@every .5s", + b"@every 3.5s", + b"@every 5.0s", + b"@every 5\ts", + b"@every \xc3\xa9s", + b"\xff @every \xff 5s \xfe", + b"@every 5s\xff", + ]: + write_seed("every_parse", i, raw) + i += 1 + + # Non-grammar prefixes and shapes (cron / @once adjacency). + for raw in [ + b"@once", + b"@hourly", + b"@daily", + b"@weekly", + b"*/5 * * * *", + b"0 0 * * *", + b"every 5s", + b"5s", + b"@every 5", + b"@every s", + ]: + write_seed("every_parse", i, raw) + i += 1 + + # Byte payloads ≥ 24 bytes: the boundary-arithmetic leg folds + # adversarial (next_fire_at, now, interval) triples straight out of + # the bytes — the i64::MAX neighborhood, negative shapes, d-blowups. + for raw in [ + b"@every 9223372036854775807s skip-forward-triple payload XXXXX", + b"\x00" * 24, + b"\xff" * 24, + bytes([ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, # next = i64::MAX + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, # now = 2^62 + 0x80, 0xC8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, # interval = 250000 + ]), + bytes([ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, # next = i64::MIN + 1 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, # now = i64::MAX + 0x80, 0x92, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, # interval = negative + ]), + ]: + write_seed("every_parse", i, raw) + i += 1 + + def main(): payload_codec_seeds() + every_parse_seeds() if __name__ == "__main__": diff --git a/fuzz/shared/Cargo.toml b/fuzz/shared/Cargo.toml index 31387cd..a2208e6 100644 --- a/fuzz/shared/Cargo.toml +++ b/fuzz/shared/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" [dependencies] alkstore = { path = "../../alkstore" } +alkstore-sqlite = { path = "../../alkstore-sqlite" } +alkstore-postgres = { path = "../../alkstore-postgres" } +alkstore-mem = { path = "../../alkstore-mem" } serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/fuzz/shared/src/every_parse.rs b/fuzz/shared/src/every_parse.rs new file mode 100644 index 0000000..8f18ae6 --- /dev/null +++ b/fuzz/shared/src/every_parse.rs @@ -0,0 +1,276 @@ +//! Invariant logic for the `every_parse` target (docs/research/ +//! fuzzing.md §3.2): the three one-owner `@every` parsers (ADR-009 §2's +//! grammar, ADR-012 §2's one-owner rule) driven **differentially** +//! through the engines' `#[doc(hidden)]` re-exports — no-panic on any +//! string, typed rejection, three-way agreement (the Ok/Err partition +//! and the `Ok` value; error *identity* is deliberately not pinned — +//! the SQLite surface's `Result` vs pg/mem's +//! `Result`/`InvalidSpec` is a known, typed asymmetry), the +//! overflow posture, and the `n <= 0` / giant-`n` arms. + +use alkstore::Error; +use alkstore_mem as mem_engine; +use alkstore_postgres as pg_engine; +use alkstore_sqlite as sqlite_engine; + +pub fn fuzz_every_parse(data: &[u8]) { + let spec = String::from_utf8_lossy(data); + assert_parse_agreement(spec.as_ref()); + assert_parse_battery(); + assert_skip_battery(); + assert_skip_triples(data); +} + +/// pg and mem reject grammar-violating shapes with their own typed +/// error, `Error::InvalidSpec` — never a panic, never a silent `Ok` +/// on a shape the authored tests reject. +fn assert_typed_rejection(spec: &str, engine: &str) { + let result = match engine { + "pg" => pg_engine::parse_every_interval(spec), + _ => mem_engine::parse_every_interval(spec), + }; + match result { + Ok(_) | Err(Error::InvalidSpec { .. }) => {} + Err(other) => panic!("{engine} rejects must be `InvalidSpec`, got {other:?} for {spec:?}"), + } +} + +/// One invocation of the three parsers over a lossy-decoded spec: +/// three-way agreement on the Ok/Err partition and the `Ok` value +/// (SQLite's `Err` payloads are `String`s — the accepted asymmetry — so +/// the SQLite comparison is partition-and-value only). +fn assert_parse_agreement(spec: &str) { + assert_typed_rejection(spec, "pg"); + assert_typed_rejection(spec, "mem"); + let sqlite_result = sqlite_engine::parse_every_interval(spec).map_err(|_| ()); + let pg_result = pg_engine::parse_every_interval(spec).map_err(|_| ()); + let mem_result = mem_engine::parse_every_interval(spec).map_err(|_| ()); + assert_eq!( + pg_result, mem_result, + "pg and mem must agree on the Ok/Err partition for {spec:?}" + ); + match pg_result { + Ok(interval) => { + assert_eq!( + sqlite_result, + Ok(interval), + "sqlite must accept {spec:?} with pg/mem's interval" + ); + } + Err(()) => { + assert_eq!( + sqlite_result, + Err(()), + "sqlite must reject what pg/mem reject for {spec:?}" + ); + } + } +} + +type Engine = (&'static str, fn(&str) -> Result); + +fn engines() -> Vec { + vec![ + ("sqlite", |s: &str| { + sqlite_engine::parse_every_interval(s).map_err(|_| ()) + }), + ("pg", |s: &str| { + pg_engine::parse_every_interval(s).map_err(|_| ()) + }), + ("mem", |s: &str| { + mem_engine::parse_every_interval(s).map_err(|_| ()) + }), + ] +} + +/// The grammar battery: shapes the authored tests already reject/accept +/// — pinned on every invocation so neither the fuzz path nor a corpus +/// replay ever observes drift (a silent `Ok` on a known-bad shape, a +/// changed interval value, a lost reject). Giant-`n` arms: the +/// `9223372036854775807` neighborhood and digit overflow at exactly +/// `i64::MAX/86400`. +fn assert_parse_battery() { + for (spec, want) in accept_battery() { + for (engine_name, engine) in engines() { + assert_eq!( + engine(spec), + Ok(want), + "{engine_name} must accept the grammar-valid {spec:?}" + ); + } + } + for spec in reject_battery() { + for (engine_name, engine) in engines() { + assert!( + engine(spec).is_err(), + "{engine_name} must reject the grammar-violating {spec:?}" + ); + } + } +} + +fn accept_battery() -> Vec<(&'static str, i64)> { + vec![ + ("@every 1s", 1), + ("@every 5s", 5), + ("@every 9s", 9), + ("@every 17s", 17), + ("@every 42m", 2520), + ("@every 1m", 60), + ("@every 90m", 5400), + ("@every 2h", 7200), + ("@every 24h", 86_400), + ("@every 1d", 86_400), + ("@every 7d", 604_800), + ("@every 007s", 7), + ("@every 007m", 420), + ("@every 000000042h", 151_200), + ("@every 106751991167300d", 9_223_372_036_854_720_000), + ("@every 9223372036854775807s", i64::MAX), + ("@every 9223372036854775806s", i64::MAX - 1), + ] +} + +fn reject_battery() -> Vec<&'static str> { + vec![ + "", + "@every", + "@every ", + "@every 0s", + "@every -5s", + "@every +5s", + "@every 5", + "@every s", + "@every 5sx", + "@every 5S", + "@every 5s", + "@every 5s ", + "@every 3.5s", + "@every 9223372036854775808s", + "@every 9223372036854775807m", + "@every 106751991167301d", + "@every 18446744073709551616s", + "@every 00m", + "every 5s", + "5s", + "*/5 * * * *", + "0 0 * * *", + "@once", + "@hourly", + "@daily", + "@weekly", + "@minute", + ] +} + +/// The overflow-posture battery for the next-boundary arithmetic: +/// adversarial `(next_fire_at, now, interval)` triples (the `i64::MAX` +/// neighborhood, negative shapes, `d`-unit multiplier blowups) — +/// reject-or-saturate semantics, never wrapping or panicking. The +/// three implementations are asserted equal over the whole domain +/// (post-clamp they carry pg's pinned shape identically). +fn assert_skip_battery() { + for &(next_fire_at, now, interval) in TRIPLES { + assert_skip_posture(next_fire_at, now, interval); + } +} + +const TRIPLES: &[(i64, i64, i64)] = &[ + (0, 0, 0), + (0, 0, 1), + (0, 1, 1), + (5, 4, 60), + (5, 3, 60), + (i64::MAX, i64::MAX, 1), + (i64::MAX - 5, i64::MAX, 1), + (i64::MAX - 100, i64::MAX, 86_400), + (i64::MAX - 100, i64::MAX, 86_400 * 30), + (i64::MAX / 2, i64::MAX, i64::MAX / 2), + (i64::MAX / 2, i64::MAX, i64::MAX), + (i64::MAX, i64::MAX, i64::MAX), + (i64::MIN, i64::MIN, 1), + (i64::MIN, i64::MIN, 86_400), + (i64::MIN, i64::MAX, 1), + (i64::MIN, i64::MAX, 86_400 * 30), + (i64::MIN, 0, 86_400), + (0, i64::MAX, 86_400 * 365), + (5, 4, 0), + (5, 4, -60), + (i64::MAX, i64::MIN, -1), + (i64::MIN, i64::MAX, i64::MIN), + (0, i64::MAX, i64::MIN), + (86_400, 86_399, 86_400 * u32::MAX as i64), +]; + +fn assert_skip_posture(next_fire_at: i64, now: i64, interval: i64) { + let a = sqlite_engine::skip_forward(next_fire_at, now, interval); + let b = pg_engine::skip_forward(next_fire_at, now, interval); + let c = mem_engine::skip_forward(next_fire_at, now, interval); + assert_eq!( + a, b, + "sqlite and pg skip-forward must agree for ({next_fire_at}, {now}, {interval})" + ); + assert_eq!( + b, c, + "pg and mem skip-forward must agree for ({next_fire_at}, {now}, {interval})" + ); + + // Saturation: the result is either the `i64::MAX` clamp or a value + // strictly beyond `now` — no wrap into the past, ever. + assert!( + a == i64::MAX || a > now, + "skip-forward must land strictly beyond `now` or saturate: got {a} for ({next_fire_at}, {now}, {interval})" + ); +} + +/// Adversarial triples folded straight out of the input bytes — the +/// whole `(next_fire_at, now, interval)` domain through the fuzz path +/// and every ≥24-byte corpus seed. +fn assert_skip_triples(data: &[u8]) { + let (chunks, remainder) = data.as_chunks::<24>(); + for chunk in chunks { + assert_skip_triple(chunk); + } + let mut tail = [0u8; 24]; + tail[..remainder.len()].copy_from_slice(remainder); + assert_skip_triple(&tail); +} + +fn assert_skip_triple(chunk: &[u8]) { + let next_fire_at = i64::from_le_bytes(chunk[..8].try_into().expect("slice is 8 bytes")); + let now = i64::from_le_bytes(chunk[8..16].try_into().expect("slice is 8 bytes")); + let interval = i64::from_le_bytes(chunk[16..24].try_into().expect("slice is 8 bytes")); + assert_skip_posture(next_fire_at, now, interval); +} + +#[cfg(test)] +mod corpus_replay { + use super::*; + use std::path::PathBuf; + + #[test] + fn committed_corpus_replays_through_the_invariants() { + let corpus = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../corpus/every_parse"); + let mut count = 0usize; + for entry in std::fs::read_dir(&corpus).expect("corpus directory is committed") { + let path = entry.expect("corpus entry readable").path(); + let data = std::fs::read(&path).expect("corpus entry readable"); + fuzz_every_parse(&data); + count += 1; + } + assert!( + count >= 48, + "committed seed corpus is present, found {count}" + ); + } + + #[test] + fn invariants_hold_without_corpus() { + fuzz_every_parse(b""); + fuzz_every_parse(b"@every 5s"); + fuzz_every_parse(b"@every 106751991167301d"); + fuzz_every_parse(b"\xff @every \xff 5s \xfe"); + fuzz_every_parse(&[0u8; 24]); + fuzz_every_parse(&(i64::MIN as i128).to_le_bytes()); + } +} diff --git a/fuzz/shared/src/lib.rs b/fuzz/shared/src/lib.rs index 3bbef47..9d47df5 100644 --- a/fuzz/shared/src/lib.rs +++ b/fuzz/shared/src/lib.rs @@ -4,4 +4,5 @@ //! CI pattern) without a nightly toolchain. pub mod arbitrary_value; +pub mod every_parse; pub mod payload_codec; diff --git a/tasks/fuzz-target-every-parse.md b/tasks/fuzz-target-every-parse.md index fdfa5d7..3438e04 100644 --- a/tasks/fuzz-target-every-parse.md +++ b/tasks/fuzz-target-every-parse.md @@ -1,7 +1,7 @@ --- id: fuzz-target-every-parse name: Fuzz target — `every_parse` (the three `@every` parsers, differential) -status: pending +status: completed depends_on: [fuzz-scaffold, fuzz-parser-exposure] scope: moderate risk: medium @@ -73,17 +73,23 @@ escalate), not a task failure. ## Acceptance Criteria -- [ ] `fuzz_targets/every_parse.rs` + `shared/src/every_parse.rs` +- [x] `fuzz_targets/every_parse.rs` + `shared/src/every_parse.rs` exist; `cargo fuzz build` builds the target -- [ ] All five §3.2 invariant classes implemented and exercised by both +- [x] All five §3.2 invariant classes implemented and exercised by both the fuzz path and the replay module; the three-way agreement asserted on every input (fuzz) and every seed (replay) -- [ ] Seed corpus committed, deterministic-generated, gitignore +- [x] Seed corpus committed, deterministic-generated, gitignore negation in place -- [ ] `cargo test --manifest-path fuzz/shared/Cargo.toml` green; +- [x] `cargo test --manifest-path fuzz/shared/Cargo.toml` green; `shared` clippy/fmt gates green -- [ ] Root workspace gates still green; substrate diff still empty -- [ ] Any three-way divergence found during target development is +- [x] Root workspace gates still green; substrate diff still empty + *(amended at implementation, 2026-10-10 — see Notes: the target + found a real no-panic/overflow-posture finding in `skip_forward`, + dispositioned inline per the task's own finding posture; the + substrate delta is two keyword-free lines in the re-derived + `queue_ops.rs`, registered as PROVENANCE D-38; lineage body + untouched)* +- [x] Any three-way divergence found during target development is recorded in Notes with its disposition (fixed / escalated), not silently absorbed @@ -101,8 +107,106 @@ escalate), not a task failure. ## Notes -> To be filled by implementation agent +Decisions of record the implementation made that the description didn't +pin: + +- **Two real findings, both in `skip_forward` (the boundary leg), + dispositioned fixed inline** (per this task's risk note, the + campaign task's posture — small crate-side fixes ride the task that + finds them): + 1. **Division-by-zero panic + negative-`interval` under-wrap** — + SQLite and mem's `skip_forward` cast `interval` straight into + `i128` (pg had `interval.max(1)`); `interval == 0` panicked on + i128 division, and a negative `interval` skipped the high-side + guard so `next < i64::MIN` wrapped silently. Fix: the clamp, pg's + committed shape. With `interval >= 1` the under-flow path is + unreachable, so the fix is exactly pg's body — no extra guard was + added beyond it. + 2. **i64 gap subtraction before the i128 cast (all three engines, + including pg)** — `(now - next_fire_at) as i128` computed the + difference in i64: panics (debug overflow) / wraps silently + (release) when `(next_fire_at, now)` straddle the full domain + (`now = i64::MIN`-adjacent, `next_fire_at = i64::MAX`-adjacent). + The 128-bit intermediates story had a hole at its first line. Fix: + `now as i128 - next_fire_at as i128` — same one line, all three. + Observable reachability: both pre-fix paths are reachable only + outside the parsers' grammar domain (`n <= 0` rejected ⇒ callers + pass `interval >= 1`; `|gap| < i64` range in every clock-domain + call) — no engine-internal behavior change; the invariant now holds + over the whole domain. SQLite's delta registered as + `substrate/PROVENANCE.md` **D-38** (queue_ops.rs is the re-derived + half, D-12's own — D-31/D-37's precedent for owned-code deltas in + the register); mem needs no provenance entry (engine-owned + `scheduler.rs`), and pg's one-line delta is engine-owned likewise. +- **(a)-companion leg not built.** The optional `schedule()`-driven + register-posture leg stayed unbuilt: the register-path posture (parse + → first-boundary `checked_add` → reject `InvalidSpec`) is suite-pinned + already, and driving the mem factory from `shared` would pull a + tokio runtime into the stable gate crate for one redundant leg. +- **`skip_forward` three-way equality asserted, not just no-panic.** + Post-fix the three bodies are lexically identical, so the target + goes further than the task text required: three-way output + equality on *every* `(next_fire_at, now, interval)` triple (fixed + adversarial battery + triples folded out of the input bytes at + 24-byte stride), plus the saturation pin + (`i64::MAX` clamp or strictly-beyond-`now`, never a past value). +- **Error identity left unpinned as specified**: SQLite's + `Result` vs pg/mem's `InvalidSpec` — the differential + pins partition-and-value; the typed-rejection check (pg/mem must + reject with `Error::InvalidSpec`, never another variant) runs ahead + of the agreement assert. +- **Corpus growth noise after the smoke campaign**: a 180 s detached + smoke (`run-detached.sh every_parse -max_len=4096 + -use_value_profile=1`, ~737k execs, 0 crash/oom/timeout — the + campaign task re-runs the full budget) grew `corpus/every_parse` to + 686 files; the grown additions were pruned back to the 66 committed + generator seeds since corpus-policy reconciliation + (grown-corpus disposition, the seed-promotion posture) is the + campaign task's named AC. The `!corpus/every_parse` negation does + un-ignore grown additions in that dir — the same shape alksocks + shipped, so the tension is the campaign task's to resolve, noted + here for context. ## Summary -> To be filled on completion \ No newline at end of file +Landed the `every_parse` differential target (2026-10-10): the §3.2 +surface — all three one-owner `parse_every_interval` implementations +driven through the `fuzz-parser-exposure` `#[doc(hidden)]` re-exports, +plus all three `skip_forward` boundary postures. + +- **`fuzz/shared/src/every_parse.rs`** — the invariant logic (stable + toolchain, replayable): typed-rejection pin (pg/mem rejects are + `Error::InvalidSpec` only), three-way agreement on partition + + `Ok` value for arbitrary lossy-decoded strings, a fixed grammar + battery (17 accept shapes with pinned interval values incl. + leading-zero and the `i64::MAX`/`i64::MAX/86400`-neighborhood + giant-`n` arms; 27 reject shapes incl. positive-zero, negative, + whitespace/truncation, cron/`@once` adjacency and unknown units), + and the overflow-posture battery over `skip_forward` (24 fixed + adversarial triples + 24-byte-stride triples folded from the raw + input; three-way equality + saturate-or-strictly-future pin). + `#[cfg(test)]` corpus replay over the committed dir (≥48 seeds). +- **`fuzz/fuzz_targets/every_parse.rs`** + `[[bin]]` entry (the + payload_codec shape); engine path deps added to `shared`'s manifest; + lib.rs module registered. +- **66 committed seeds** from `gen_fuzz_seeds.py`'s new + `every_parse()` (registry wired); `!corpus/every_parse` gitignore + negation; `fuzz/README.md` targets-table row filled. +- **Two findings found and fixed inline** (details in Notes): + `skip_forward` division-by-zero/negative-`interval` wrap (sqlite + + mem), and the i64 gap subtraction before the i128 cast (all three + engines incl. pg). PROVENANCE D-38 records the substrate delta. +- **Smoke verdict**: 180 s detached campaign, ~737k execs, 0 + crash/oom/timeout — the fixes closed out the deterministic finding + space; grown corpus pruned to the committed seeds. + +Verified: `cargo build` clean; `cargo test` workspace green (15 ok +result groups, 0 failures); `cargo clippy --all-targets -- -D +warnings` clean; `cargo fmt --check` clean; the shared gate +`cargo test --manifest-path fuzz/shared/Cargo.toml` green; +shared clippy `-D warnings` + fmt --check green; +`cargo fuzz build` green from `fuzz/` (nightly pin; all three engines +compile under ASAN through the new bin); +`cargo check -p alkstore-mem --target wasm32-unknown-unknown` clean. +Lineage body untouched; the substrate delta is the two-line +`skip_forward` fix in the re-derived half, registered as D-38. \ No newline at end of file