These two land together on purpose. Fixing the encoder alone changes nothing for the blobs already in the zone, because emit skips whatever is already present. #86 — klauspost/compress omits the zstd Frame_Content_Size field for inputs under 256 bytes, which the format permits. Reference libzstd never does, so the NWN client — which sizes its output buffer from ZSTD_getFrameContentSize and has therefore never met a frame without one — rejected roughly 6% of our blobs outright. Any single one stops a sync dead, so no client could complete a sync of the live manifest. No encoder option changes this, so emit re-headers the affected frames into the shape libzstd itself emits: Single_Segment_flag set, Window_Descriptor dropped, and the freed byte spent on a one-byte Frame_Content_Size. Same length in, same length out. Verified against the zstd CLI end to end: a real emitted 230-byte blob now reports its decompressed size where it previously reported none. emitter_version goes to 2, so assemble refuses to merge an index written by the encoder that omitted the field. #85 — a published blob was verified by exactly one thing, a player's client, at download time. `nwsync verify <manifest-sha1>` now reads a manifest and its blobs back through the public pull zone with no credential, decompresses and hashes every one, and reports missing / malformed framing / size mismatch / hash mismatch per blob. `--sample N` makes a routine check cheap against a manifest that is ~69,000 blobs and 15 GB. `emit --verify` applies the same check where emit would otherwise trust presence, and replaces a stored blob that is not what its name claims — which is what makes the #86 blobs repairable. Both new checks assert the frame property, not just a round trip. Round-tripping cannot see this class of fault: both the zstd CLI and Go's decoder stream such a frame happily, being more capable decoders than the client's, which is how the defect reached production and survived an audit. Refs #54, #55, #59, #75, sow-platform#79. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,13 @@ type fakeZone struct {
|
||||
objects map[string][]byte
|
||||
puts []string
|
||||
failOn func(key string) bool // when true, the PUT fails
|
||||
url string // base the same objects are readable at
|
||||
}
|
||||
|
||||
// pullZone reads the fake zone the way the public pull zone is read: plain
|
||||
// unauthenticated GETs, no storage API.
|
||||
func (z *fakeZone) pullZone() blobSource {
|
||||
return newPullZone(z.url)
|
||||
}
|
||||
|
||||
func newFakeZone(t *testing.T) (*fakeZone, func(string) string) {
|
||||
@@ -28,6 +35,7 @@ func newFakeZone(t *testing.T) (*fakeZone, func(string) string) {
|
||||
zone := &fakeZone{objects: map[string][]byte{}}
|
||||
server := httptest.NewServer(zone)
|
||||
t.Cleanup(server.Close)
|
||||
zone.url = server.URL + "/sow-nwsync"
|
||||
getenv := func(name string) string {
|
||||
switch name {
|
||||
case "NWSYNC_STORAGE_ZONE":
|
||||
|
||||
Reference in New Issue
Block a user