{"record": "correction", "issued_at": 1787675457, "affects": ["2026-08-23", "2026-08-24"], "what_was_wrong": "Day boundaries were cut at UTC+8 (the build host's local midnight) instead of true UTC, because time.mktime() reads a struct_time as local time and silently ignored the parsed +0000. The tape column is named snapshot_ts_utc_epoch, so anyone grouping by true UTC computed a different set of rows and a different root, and would reasonably have concluded the anchoring claim was false.", "found_by": "an external reviewer's agent, reproducing the roots from published data alone and reporting 12,301 rows for 2026-08-23 where we had published 7,085", "effect": "every root published before this correction covered the wrong 24-hour window", "superseded_roots": [{"date": "2026-08-23", "rows": 7085, "merkle_root": "f891c229cdb8a8b7604dee6f9001882b5dbfe3535087ba4b03ecf052f91c7fe5", "prev_chained_root": "0000000000000000000000000000000000000000000000000000000000000000", "chained_root": "c678281c45889395467589a277d5bd2bcbe6901d750cdaea24b0cb27c16860ab", "anchored_at": 1787671115, "leaf": "sha256 of the row's line in gpu-price-tape.csv.gz, leaves sorted by hash", "tree": "binary merkle, sha256 over concatenated hex, last node duplicated on odd levels", "chain": "sha256(prev_chained_root + merkle_root), both lowercase hex", "ots": "stamped"}, {"date": "2026-08-24", "rows": 23373, "merkle_root": "1829cc33d410cc231afdc5f8aae13b45d3afe0e3259872798d777f55961a2efc", "prev_chained_root": "c678281c45889395467589a277d5bd2bcbe6901d750cdaea24b0cb27c16860ab", "chained_root": "5c8b72a8b7d6050fae097b51878439565cd669b32f2363105878c67e18e5053d", "anchored_at": 1787671118, "leaf": "sha256 of the row's line in gpu-price-tape.csv.gz, leaves sorted by hash", "tree": "binary merkle, sha256 over concatenated hex, last node duplicated on odd levels", "chain": "sha256(prev_chained_root + merkle_root), both lowercase hex", "ots": "stamped"}], "fix": "boundaries now computed with calendar.timegm (timezone-independent); the day boundary, leaf terminator rule, leaf sort order, odd-node rule and proof URL are now stated in every root record so none of it has to be guessed"}
{"date": "2026-08-23", "rows": 12301, "merkle_root": "644ebadc36b50e59621bf6c7474cb4de15b6c44695e7b0132ddf7e87d8f92a17", "prev_chained_root": "0000000000000000000000000000000000000000000000000000000000000000", "chained_root": "f6e3c7267289a915b11095aafe9230ef69c9fe03d93b05f4cc2cf5e311ff7e35", "anchored_at": 1787675472, "day_boundary": "00:00:00Z to 24:00:00Z, TRUE UTC \u2014 snapshot_ts >= start AND < start+86400", "leaf": "sha256 of the row's line from gpu-price-tape.csv.gz, verbatim, with the line terminator (CR and/or LF) stripped and nothing else changed", "leaf_order": "leaves sorted ASCENDING as lowercase hex strings, before any pairing", "tree": "binary merkle over the sorted leaves: sha256 of the two child hex strings concatenated as text; on a level with an odd count the LAST node is duplicated and paired with itself", "chain": "sha256(prev_chained_root + merkle_root), both lowercase hex, ASCII concatenation", "genesis": "0000000000000000000000000000000000000000000000000000000000000000", "proof": "/data/roots/2026-08-23.txt.ots", "proof_covers": "the chained_root, as the sole line of that .txt file plus a trailing newline", "verify": "ots verify <the .ots file>  (OpenTimestamps client)", "ots": "stamped"}
{"date": "2026-08-24", "rows": 23175, "merkle_root": "4b3de2231bf54a29c89fc97865bf1d054176d7da5c4ac4773fbe621ce74db73d", "prev_chained_root": "f6e3c7267289a915b11095aafe9230ef69c9fe03d93b05f4cc2cf5e311ff7e35", "chained_root": "cc5df2d2b5184240f834c27b2445b52b4ca3526ba6be2c63a852937b22d56c83", "anchored_at": 1787675584, "day_boundary": "00:00:00Z to 24:00:00Z, TRUE UTC \u2014 snapshot_ts >= start AND < start+86400", "leaf": "sha256 of the row's line from gpu-price-tape.csv.gz, verbatim, with the line terminator (CR and/or LF) stripped and nothing else changed", "leaf_order": "leaves sorted ASCENDING as lowercase hex strings, before any pairing", "tree": "binary merkle over the sorted leaves: sha256 of the two child hex strings concatenated as text; on a level with an odd count the LAST node is duplicated and paired with itself", "chain": "sha256(prev_chained_root + merkle_root), both lowercase hex, ASCII concatenation", "genesis": "0000000000000000000000000000000000000000000000000000000000000000", "proof": "/data/roots/2026-08-24.txt.ots", "proof_covers": "the chained_root, as the sole line of that .txt file plus a trailing newline", "verify": "ots verify <the .ots file>  (OpenTimestamps client)", "ots": "stamped"}
{"record": "sealing", "issued_at": 1787682088, "affects": ["2026-08-23", "2026-08-24"], "what_changed": "Each anchored day now also exists as its own file that is written once and never again, plus a manifest that content-addresses the sealed tape, the root file and the .ots proof by sha256. No root value changed; nothing already published was rewritten. This record is appended rather than editing the day records above, because those are published lines.", "why": "The tape was one rolling, mutable file. A verifier fetched a current roots file and whatever copy of the tape their cache held, hashed a different set of rows, and correctly concluded the anchoring claim was false. We first corrected the cache headers, and an external reviewer's agent then pointed out that no TTL can make a moving file agree with a fixed root. A sealed day cannot go stale because it cannot move.", "raised_by": "an external reviewer's agent, on pangle.online/forum, 2026-08-25", "discover": "/data/days/index.json", "manifest": "/data/days/{date}.json", "pin": "Fetch each file named in a manifest and check its sha256 against the manifest. Once pinned, no cache, mirror or proxy can change what you are verifying.", "rolling_file": "/data/gpu-price-tape.csv.gz still exists and only has to be right about today; sealed days are the citable artifact."}
{"record": "reseal", "issued_at": 1787682645, "affects": ["2026-08-23", "2026-08-24"], "what_changed": "The sealed per-day tape files were rewritten with a deterministic gzip header (mtime pinned to 0) and their manifests updated with the new sha256. NO root value changed \u2014 same rows, same leaves, same merkle and chained roots. Only the compressed bytes changed.", "why": "gzip stamps the compression time into every file it writes, so sealing the same rows twice produced two different sha256 digests. The manifest would still have let you check the copy we served, but you could not have REBUILT our file from the rows and got our hash \u2014 which is most of the point of content-addressing it. Found by sealing the same day twice in a test and noticing the digests disagreed.", "effect": "Sealed days are now byte-reproducible: anyone holding a day's rows can rebuild our exact file and get our exact hash.", "if_you_pinned_the_old_hash": "The old digest is superseded and is recorded here rather than erased: 2026-08-23 was 1d50d0a4d5da7347, 2026-08-24 was 5e70649abb9e22b4. The roots those files attest to are unchanged, so nothing you verified became wrong."}
