Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / fuzz / Cargo.lock
Author[]Andy Green <andy@warmcat.com> 2026-10-04 12:12 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-10-05 06:32 UTC
Tree2a6187ed9be5357cda341200a130f2ea00692e33   Raw Patch
 
npro-test: sync the transcripts with C lws main-dev bd9c8170
npro-test: sync the transcripts with C lws main-dev bd9c8170

C's series measuring and closing the gaps in its state table's test
coverage added nine api-test-sansio cases: an h1 answer before the body,
a body completing after the answer, an empty POST answered from its
headers, a CONNECT going raw, a digest auth retry on h1 and ws clients,
h2c upgrades with and without a body, and ws over h2 with the peer's
close crossing ours.  The fifty transcripts npro had are unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kg5Eemy68ZaqDBcUJQG6J
diff --git a/crates/npro-test/transcripts/C-COMMIT b/crates/npro-test/transcripts/C-COMMIT index 9bb4339..7590317 100644 --- a/crates/npro-test/transcripts/C-COMMIT +++ b/crates/npro-test/transcripts/C-COMMIT @@ -1 +1 @@ -1ba28796b2db62a255720c308498eff0325b3e83 metrics: release tags a close adds to the wsi after its caliper report +bd9c8170d7d492e8bb3c5a68e470ff21d673fd3e client: a quic wsi racing tcp reads its server's first datagram diff --git a/crates/npro-test/transcripts/README.lws.md b/crates/npro-test/transcripts/README.lws.md index 4e91a31..f757592 100644 --- a/crates/npro-test/transcripts/README.lws.md +++ b/crates/npro-test/transcripts/README.lws.md @@ -103,8 +103,17 @@ does only this: |`ws-server-huge-frame`|server|as `h1-ws-server`: after the upgrade, the peer sends a masked frame whose length is 256MiB + 1. lws closes with status 1009, `huge frame`| |`ws-server-pmd-rsv1-continuation`|server|as `h1-ws-server`, on a second vhost, `sansio-pmd`, with `permessage-deflate` (no parameters). The peer asks for a ws upgrade to it offering `permessage-deflate`, which is accepted, then sends an unfinished text frame `He` and a continuation with RSV1: lws closes with status 1002, `rsv bits`, and once the peer answers the close, shuts the connection down| |`h2-ws-peer-close`|server|a sixth vhost, `sansio-h2ws`, taking h2 with prior knowledge, with the ws protocols of `sansio`. The peer sends the preface and SETTINGS, then an extended CONNECT (RFC 8441) for a ws stream on sid 1 speaking `echo`, which is accepted with 200; then one DATA frame holding, masked, a close with status 1000 and after it a ping `p`. lws answers the close with the peer's own 1000 and END_STREAM, reads nothing after it, so the ping gets no pong, and resets the stream with NO_ERROR, since the peer has not ended its side: not REFUSED_STREAM, which is only for a refused upgrade| +|`h2-ws-close-crossed`|server|as `h2-ws-peer-close`, whose `echo` starts the close itself, going away (1001 `bye`), when it is sent the text `Close`. The peer sends `Close` in one DATA frame, while lws' writes take nothing, so its close is still waiting to go when the peer's own close, status 1000, arrives in the next DATA frame, with END_STREAM: the connection goes on reading for its streams. The closes have crossed: once writes go again, lws sends only the answer to the peer's, with the peer's own 1000 and END_STREAM, not its own close. The peer has ended the stream, so it is not reset| |`h1-post-no-length`|server|as `h1-uri-*`, on `sansio-uri`. The peer sends, in one read, `POST /x?a=1` with neither `Content-Length` nor `Transfer-Encoding`, and behind its head `GET /y?b=2`. The POST has no body (RFC 9112 6.3): lws answers it (path `/x`, args `a=1`), then serves the GET as the next request on the kept-alive connection, rather than taking it as the POST's body and reading until the close| |`h1-connect-rejected-ua`|server|as `h1-reqline-*`, on `sansio-uri`, in a context that turns away a user agent containing `badbot` with `403 Go away`. The peer sends a CONNECT for `example.com:443` saying it is `badbot/1`: it is refused like any other request of its, 403 with the status page, and the connection shut down, rather than handed to the fallback role first| +|`h1-post-zero-answered`|server|as `h1-404-keepalive`, on `sansio-404`, while the connection takes at most 4 bytes a write. The peer sends `POST /cb/y` saying `Content-Length: 0`: `http` answers it from its headers, redirected to the 404 document with a 302, and completes the transaction, the answer still going. The empty body's completion is not given to `http`, which answers from it, as no body's is once the transaction is complete: there is the one answer. Then `GET /cb/y` on the kept-alive connection, redirected the same| +|`h1-body-done`|server|as `h1-uri-*`, on `sansio-uri`, whose app answers `/body-done` from the request body's first piece, 200 `text/plain` with content length 3 and the body `ok\n`, and completes the transaction then. The peer sends `POST /body-done` with `Content-Length: 5`, then the body `abcde` in one piece: the answer goes, the body's completion is not given to the app after it completed, and `GET /x` on the kept-alive connection is answered as usual| +|`h1-answer-before-body`|server|as `h1-uri-*`, on `sansio-uri`, while the connection takes only 65 bytes of what is written. The peer sends `POST /x` with `Content-Length: 5`, and no body yet. The app's answer to it, path `/x`, goes as it does for a GET: its headers from the request, its body `/x\n` from the writeable, which comes before the request body has, and it completes the transaction. Only the headers and the body's first byte go; the request body `abcde` arriving meanwhile is not read. Once writes go again, the rest of the answer goes and the request body is read and discarded, and `GET /y` on the kept-alive connection is answered as usual| +|`h2c-upgrade`|server|as `h1-uri-*`, on `sansio-uri`, which takes h2 only by upgrade. The peer sends `GET /x` asking to upgrade to `h2c`, with `HTTP2-Settings` saying `MAX_CONCURRENT_STREAMS` 100: lws answers 101. Then the peer's preface and SETTINGS, and the ack of the server's: the server's SETTINGS is its first h2 frame, and the GET, which is stream 1, is answered on it through the app, path `/x`, ending the stream| +|`h2c-upgrade-with-body`|server|as `h2c-upgrade`, but a `POST /x` with `Content-Length: 3` and its body: a request with a body of its own is not upgraded, what follows its head would be read as h2. lws answers 400 with the usual status page| +|`h1-connect-raw`|server|a vhost `sansio-raw` whose fallback (`listen_accept_role` `raw-skt`, `listen_accept_protocol` `raw-echo`) is a raw protocol, `raw-echo`, which answers a CONNECT's head as a tunnel would, `200 Connection established`, and echoes anything else. The peer sends `CONNECT sansio-raw:443` with `Host: sansio-raw`: the connection becomes raw and `raw-echo` is given the head, its first rx, and answers it; then the peer sends `hello` through it, which comes back| +|`h1-client-digest-retry`|client|as `h1-client-get`, with the credentials `user` / `pass`. The peer answers `401 Unauthorized` with a digest challenge (RFC 7616, realm `sansio`, qop `auth`), keeping the connection and with `Content-Length: 0`: the client asks for `/x` again on the same connection, with its `Authorization: Digest` response, and takes the answer to that, 200 with the body `ok`. The response's cnonce is lws' random| +|`ws-client-digest-retry`|client|as `ws-client`, sending nothing once established, with the credentials `user` / `pass`: the peer answers the upgrade with the same `401` as `h1-client-digest-retry`, the client asks again on the same connection with its digest response, and the 101 to that establishes it| |`h1-short-answer`|server|as `h1-uri-*`, on `sansio-uri`, whose app answers `/short` with a head giving `content-length: 10`, sends `abc` (nothing to a HEAD) and completes the transaction. The peer sends `HEAD /short`: the answer is whole without a body, and the connection is kept alive. Then `GET /short`: the answer is 7 bytes short of its length, and kept alive, the peer would read the next answer as the rest of it, so the connection is shut down| ## Recording diff --git a/crates/npro-test/transcripts/h1-answer-before-body.json b/crates/npro-test/transcripts/h1-answer-before-body.json new file mode 100644 index 0000000..04a81b6 --- /dev/null +++ b/crates/npro-test/transcripts/h1-answer-before-body.json @@ -0,0 +1,16 @@ +{ + "format": "lws-transcript/1", + "case": "h1-answer-before-body", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 352001000, "rx": "504f5354202f7820485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a436f6e74656e742d4c656e6774683a20350d0a0d0a"}, + {"t": 352001000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20330d0a0d0a2f"}, + {"t": 352002000, "rx": "6162636465"}, + {"t": 352003000, "tx": "780a"}, + {"t": 352004000, "rx": "474554202f7920485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 352004000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20330d0a0d0a2f790a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-body-done.json b/crates/npro-test/transcripts/h1-body-done.json new file mode 100644 index 0000000..35ceffe --- /dev/null +++ b/crates/npro-test/transcripts/h1-body-done.json @@ -0,0 +1,15 @@ +{ + "format": "lws-transcript/1", + "case": "h1-body-done", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 351001000, "rx": "504f5354202f626f64792d646f6e6520485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a436f6e74656e742d4c656e6774683a20350d0a0d0a"}, + {"t": 351002000, "rx": "6162636465"}, + {"t": 351002000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20330d0a0d0a6f6b0a"}, + {"t": 351003000, "rx": "474554202f7820485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a0d0a"}, + {"t": 351003000, "tx": "485454502f312e3120323030204f4b0d0a636f6e74656e742d747970653a20746578742f706c61696e0d0a636f6e74656e742d6c656e6774683a20330d0a0d0a2f780a"} + ] +} diff --git a/crates/npro-test/transcripts/h1-client-digest-retry.json b/crates/npro-test/transcripts/h1-client-digest-retry.json new file mode 100644 index 0000000..7e88a90 --- /dev/null +++ b/crates/npro-test/transcripts/h1-client-digest-retry.json @@ -0,0 +1,15 @@ +{ + "format": "lws-transcript/1", + "case": "h1-client-digest-retry", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 356001000, "tx": "474554202f7820485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a636f6e6e656374696f6e3a20636c6f73650d0a0d0a"}, + {"t": 356002000, "rx": "485454502f312e312034303120556e617574686f72697a65640d0a5757572d41757468656e7469636174653a20446967657374207265616c6d3d2273616e73696f222c206e6f6e63653d2264636439386237313032646432663065386231316430663630306266623063303933222c20716f703d2261757468222c206f70617175653d223563636330363963343033656261663966303137316539353137663430653431220d0a436f6e74656e742d4c656e6774683a20300d0a0d0a"}, + {"t": 356002000, "tx": "474554202f7820485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a417574686f72697a6174696f6e3a2044696765737420757365726e616d653d2275736572222c207265616c6d3d2273616e73696f222c206e6f6e63653d2264636439386237313032646432663065386231316430663630306266623063303933222c207572693d222f78222c20716f703d617574682c206e633d30303030303030312c20636e6f6e63653d22336166613236623530613461303936353237363536656564333131653836616231363733393837366335626361633861626534383532623238613938653737653136386638646233373632643134653232656237616637323264623534353464306539656130306234346635646230386163343631613932633964306663306634306365316233333465633732653265626364656666373138633433653762623466356561663162666639333938306330326432386365396665656565336636363535303164303530626361363964366364613836663832613665363733643762643963666664353134653231633630343866633738313763333131653135222c20726573706f6e73653d223563616437626265636138316264643535353033393565363037376431653433222c20616c676f726974686d3d224d4435220d0a636f6e6e656374696f6e3a20636c6f73650d0a0d0a"}, + {"t": 356003000, "rx": "485454502f312e3120323030204f4b0d0a436f6e74656e742d4c656e6774683a20320d0a0d0a6f6b"}, + {"t": 356003000, "app_rx": "6f6b"} + ] +} diff --git a/crates/npro-test/transcripts/h1-connect-raw.json b/crates/npro-test/transcripts/h1-connect-raw.json new file mode 100644 index 0000000..aacc47f --- /dev/null +++ b/crates/npro-test/transcripts/h1-connect-raw.json @@ -0,0 +1,16 @@ +{ + "format": "lws-transcript/1", + "case": "h1-connect-raw", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 355001000, "rx": "434f4e4e4543542073616e73696f2d7261773a34343320485454502f312e310d0a486f73743a2073616e73696f2d7261770d0a0d0a"}, + {"t": 355001000, "app_rx": "434f4e4e4543542073616e73696f2d7261773a34343320485454502f312e310d0a486f73743a2073616e73696f2d7261770d0a0d0a"}, + {"t": 355001000, "tx": "485454502f312e312032303020436f6e6e656374696f6e2065737461626c69736865640d0a0d0a"}, + {"t": 355002000, "rx": "68656c6c6f"}, + {"t": 355002000, "app_rx": "68656c6c6f"}, + {"t": 355002000, "tx": "68656c6c6f"} + ] +} diff --git a/crates/npro-test/transcripts/h1-post-zero-answered.json b/crates/npro-test/transcripts/h1-post-zero-answered.json new file mode 100644 index 0000000..368a802 --- /dev/null +++ b/crates/npro-test/transcripts/h1-post-zero-answered.json @@ -0,0 +1,14 @@ +{ + "format": "lws-transcript/1", + "case": "h1-post-zero-answered", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 350001000, "rx": "504f5354202f63622f7920485454502f312e310d0a486f73743a2073616e73696f2d3430340d0a436f6e74656e742d4c656e6774683a20300d0a0d0a"}, + {"t": 350001000, "tx": "485454502f312e31203330322052656469726563740d0a6c6f636174696f6e3a202f3430342e68746d6c0d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a20300d0a0d0a"}, + {"t": 350002000, "rx": "474554202f63622f7920485454502f312e310d0a486f73743a2073616e73696f2d3430340d0a0d0a"}, + {"t": 350002000, "tx": "485454502f312e31203330322052656469726563740d0a6c6f636174696f6e3a202f3430342e68746d6c0d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a20300d0a0d0a"} + ] +} diff --git a/crates/npro-test/transcripts/h2-ws-close-crossed.json b/crates/npro-test/transcripts/h2-ws-close-crossed.json new file mode 100644 index 0000000..c0db259 --- /dev/null +++ b/crates/npro-test/transcripts/h2-ws-close-crossed.json @@ -0,0 +1,18 @@ +{ + "format": "lws-transcript/1", + "case": "h2-ws-close-crossed", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 4061000, "rx": "505249202a20485454502f322e300d0a0d0a534d0d0a0d0a000000040000000000000000040100000000"}, + {"t": 4061000, "tx": "000024040000000000000100010000000200000000000300000018000400000000000600010000000800000001000000040100000000"}, + {"t": 4062000, "rx": "00006a0104000000010207434f4e4e45435400093a70726f746f636f6c09776562736f636b65748604052f6563686f010b73616e73696f2d6832777300157365632d776562736f636b65742d76657273696f6e02313300167365632d776562736f636b65742d70726f746f636f6c046563686f"}, + {"t": 4062000, "tx": "000004080000000001000400000000040800000000000004000000002a01040000000100073a7374617475730332303000167365632d776562736f636b65742d70726f746f636f6c046563686f"}, + {"t": 4063000, "rx": "00000b000000000001818500000000436c6f7365"}, + {"t": 4063000, "app_rx": "436c6f7365"}, + {"t": 4064000, "rx": "00000800010000000188820000000003e8"}, + {"t": 4065000, "tx": "000004000100000001880203e8"} + ] +} diff --git a/crates/npro-test/transcripts/h2c-upgrade-with-body.json b/crates/npro-test/transcripts/h2c-upgrade-with-body.json new file mode 100644 index 0000000..bcd1182 --- /dev/null +++ b/crates/npro-test/transcripts/h2c-upgrade-with-body.json @@ -0,0 +1,12 @@ +{ + "format": "lws-transcript/1", + "case": "h2c-upgrade-with-body", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 353003000, "rx": "504f5354202f7820485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a436f6e6e656374696f6e3a20557067726164652c2048545450322d53657474696e67730d0a557067726164653a206832630d0a48545450322d53657474696e67733a2041414d414141426b0d0a436f6e74656e742d4c656e6774683a20330d0a0d0a616263"}, + {"t": 353003000, "tx": "485454502f312e31203430302042616420526571756573740d0a636f6e74656e742d747970653a20746578742f68746d6c0d0a636f6e74656e742d6c656e6774683a203137330d0a0d0a3c68746d6c3e3c686561643e3c6d65746120636861727365743d7574662d3820687474702d65717569763d22436f6e74656e742d4c616e67756167652220636f6e74656e743d22656e222f3e3c6c696e6b2072656c3d227374796c6573686565742220747970653d22746578742f6373732220687265663d222f6572726f722e637373222f3e3c2f686561643e3c626f64793e3c68313e3430303c2f68313e3c2f626f64793e3c2f68746d6c3e"} + ] +} diff --git a/crates/npro-test/transcripts/h2c-upgrade.json b/crates/npro-test/transcripts/h2c-upgrade.json new file mode 100644 index 0000000..e678f51 --- /dev/null +++ b/crates/npro-test/transcripts/h2c-upgrade.json @@ -0,0 +1,14 @@ +{ + "format": "lws-transcript/1", + "case": "h2c-upgrade", + "side": "server", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 0, + "steps": [ + {"t": 353001000, "rx": "474554202f7820485454502f312e310d0a486f73743a2073616e73696f2d7572690d0a436f6e6e656374696f6e3a20557067726164652c2048545450322d53657474696e67730d0a557067726164653a206832630d0a48545450322d53657474696e67733a2041414d414141426b0d0a0d0a"}, + {"t": 353001000, "tx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a436f6e6e656374696f6e3a20557067726164650d0a557067726164653a206832630d0a0d0a"}, + {"t": 353002000, "rx": "505249202a20485454502f322e300d0a0d0a534d0d0a0d0a000000040000000000000000040100000000"}, + {"t": 353002000, "tx": "00002404000000000000010001000000020000000000030000001800040000000000060001000000080000000100000004010000000000003801040000000100073a73746174757303323030000c636f6e74656e742d747970650a746578742f706c61696e000e636f6e74656e742d6c656e67746801330000030001000000012f780a"} + ] +} diff --git a/crates/npro-test/transcripts/ws-client-digest-retry.json b/crates/npro-test/transcripts/ws-client-digest-retry.json new file mode 100644 index 0000000..5587a7e --- /dev/null +++ b/crates/npro-test/transcripts/ws-client-digest-retry.json @@ -0,0 +1,14 @@ +{ + "format": "lws-transcript/1", + "case": "ws-client-digest-retry", + "side": "client", + "t0_us": 1000000000, + "t0_wall": 1767225600, + "seed": 1, + "steps": [ + {"t": 356004000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a204f766f6d7451704b4357556e5a5737744d52364771773d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 356005000, "rx": "485454502f312e312034303120556e617574686f72697a65640d0a5757572d41757468656e7469636174653a20446967657374207265616c6d3d2273616e73696f222c206e6f6e63653d2264636439386237313032646432663065386231316430663630306266623063303933222c20716f703d2261757468222c206f70617175653d223563636330363963343033656261663966303137316539353137663430653431220d0a436f6e74656e742d4c656e6774683a20300d0a0d0a"}, + {"t": 356005000, "tx": "474554202f6563686f20485454502f312e310d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a486f73743a2073616e73696f0d0a4f726967696e3a20687474703a2f2f73616e73696f0d0a417574686f72697a6174696f6e3a2044696765737420757365726e616d653d2275736572222c207265616c6d3d2273616e73696f222c206e6f6e63653d2264636439386237313032646432663065386231316430663630306266623063303933222c207572693d222f6563686f222c20716f703d617574682c206e633d30303030303030312c20636e6f6e63653d22313637333938373663356263616338616265343835326232386139386537376531363866386462333736326431346532326562376166373232646235343534643065396561303062343466356462303861633436316139326339643066633066343063653162333334656337326532656263646566663731386334336537626234663565616631626666393339383063303264323863653966656565653366363635353031643035306263613639643663646138366638326136653637336437626439636666643531346532316336303438666337383137633331316531356431383866656234343731643131396335646633316364346566306364373231222c20726573706f6e73653d223263653039303237653131653735393564313162303338386532306538303337222c20616c676f726974686d3d224d4435220d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d4b65793a20745944306c6463322b2f504f6e2f6666736f457744513d3d0d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d56657273696f6e3a2031330d0a0d0a"}, + {"t": 356006000, "rx": "485454502f312e312031303120537769746368696e672050726f746f636f6c730d0a557067726164653a20776562736f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a5365632d576562536f636b65742d50726f746f636f6c3a206563686f0d0a5365632d576562536f636b65742d4163636570743a20684a6569575179762b76796e786d2b6b52483957346655355039343d0d0a0d0a"} + ] +}
Page fetched 0s ago, creation time: 2ms (vhost etag hits: 0%, cache hits: 0%)