Repository navigation
fix(release): stabilize Linux SDK probe receipt - #71
Conversation
The source-archive compare in Build release linux 37621664130 failed only on third-party/linux-source-scope/remove-sdk-only-probe.json. The probe stores cargo build stderr; path substitution left parallel Compiling order and Finished durations (12.34s vs 2m 05s) to differ across ci-a and ci-b. Canonicalize the log, refuse leaked paths/durations, and add a scripts/release unit test so this class of drift is caught without a 2h release rebuild. Co-authored-by: Leo <leoisadev1@users.noreply.github.com>
|
|
||
| ANSI = re.compile(r'\x1b\[[0-9;]*[mK]') | ||
| # Cargo prints "12.34s" under a minute and "2m 05s" after that. | ||
| DURATION = re.compile(r'\bin (?:\d+m )?\d+(?:\.\d+)?s\b') |
There was a problem hiding this comment.
🔴 Hour-long probes destabilize source archives
When a probe exceeds an hour, DURATION leaves Cargo's hour-prefixed elapsed time in the receipt. Different run times then produce different source archives and fail the release comparison.
Learn more
Cargo can report a long build as Finished ... in 1h 02m 03s. The duration matcher recognizes only seconds or minutes plus seconds, so sdk_remove_probe accepts that line unchanged. The receipt is included in the source archive, and the release workflow compares two independently rebuilt archives. Different elapsed times make otherwise identical archives compare unequal.
Example: A first build finishes in 1h 02m 03s and a second in 1h 03m 10s. Both receipts keep those distinct values instead of in $DURATION.
Recommended fix: Match Cargo's hour-prefixed duration format as well as the existing minute and second formats. Add an hour-long case to the receipt equality tests.
| DURATION = re.compile(r'\bin (?:\d+m )?\d+(?:\.\d+)?s\b') | |
| DURATION = re.compile(r'\bin (?:\d+h )?(?:\d+m )?\d+(?:\.\d+)?s\b') |
Was this helpful? React with 👍 or 👎 to provide feedback.
| def test_two_rebuild_dirs_write_identical_probe_bytes(self): | ||
| # Linux dry run 37621664130: only remove-sdk-only-probe.json differed. | ||
| # ci-a vs ci-b, same mtime/mode, content sha c52fc0a1… vs a40e2c47…. | ||
| with tempfile.TemporaryDirectory(prefix='convt-probe-repro-') as tmp: | ||
| left_tree = Path(tmp) / 'ci-a' / 'convt-source' | ||
| right_tree = Path(tmp) / 'ci-b' / 'convt-source' | ||
| left_home = Path(tmp) / 'cargo-aaaa' | ||
| right_home = Path(tmp) / 'cargo-bbbb' | ||
| left = scope.sdk_remove_probe( | ||
| 0, | ||
| cargo_log(left_tree, left_home, ('foo v1.0.0', 'bar v2.0.0'), '12.34s', colored=True), | ||
| left_tree, | ||
| left_home, | ||
| ) | ||
| right = scope.sdk_remove_probe( | ||
| 0, | ||
| cargo_log(right_tree, right_home, ('bar v2.0.0', 'foo v1.0.0'), '2m 15s'), | ||
| right_tree, | ||
| right_home, | ||
| ) | ||
| self.assertEqual(left, right) | ||
| dumped = [] | ||
| for name, receipt in ('a.json', left), ('b.json', right): | ||
| path = Path(tmp) / name | ||
| scope.dump(path, receipt) | ||
| dumped.append(path.read_bytes()) | ||
| self.assertEqual(dumped[0], dumped[1]) | ||
| self.assertEqual(hashlib.sha256(dumped[0]).hexdigest(), hashlib.sha256(dumped[1]).hexdigest()) |
There was a problem hiding this comment.
🔍 Real probe output remains unverified
The tests exercise constructed Cargo logs, not an inspected receipt from a real probe. The repository verification standard calls for a real run and inspected output; follow up before relying on rebuild stability.
Was this helpful? React with 👍 or 👎 to provide feedback.
|
#71 normalized and sorted the probe's cargo stderr, but Linux dry run 37641703105 still differed between two identical rebuilds in exactly remove-sdk-only-probe.json. The receipt keeps the command, exit code and the packages the probe removed, which is what it is evidence of. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Linux dry run 37621664130 on
e37711cacompared two independent builds: AppImage,.deb,.rpm, linux tar.gz andsource-audit.jsonwere byte-identical. The source tarball was not.compare.pynamed one differing member:convt-source/third-party/linux-source-scope/remove-sdk-only-probe.json(shac52fc0a1…vsa40e2c47…, same mtime 1791376316 / mode 420 / uid 0). Manifests failed only because they record that tarball hash.linux-source-scope.pywrites that file after a realcargo build --offline --locked --release -p convt-cli -p convt-appwith the original lock (SDK crates temporarily moved). Every current blocker isresolved, so nothing is moved and the probe is a full compile. Cargo then writes parallelCompilinglines andFinished … in 12.34s/in 2m 05sto stderr. Substituting$SOURCEand$EMPTY_CARGO_HOMEleft that order and timing in the shipped receipt.#69 already dropped
stderrfrom the receipt. This follows up by keeping the log as evidence after a rebuild-stable rendering (sorted lines, duration placeholder, path/ANSI//tmp/rustc*substitution), recording the packages that were actually moved, refusing a receipt that still leaks a rebuild path or cargo duration, and forcingCARGO_TERM_COLOR=neveron the probe. The compare step is unchanged; the file still ships.Fixes CNV-45
Evidence
Compilinglines,12.34svs2m 15s, color, rustc tmp) dump to identicalremove-sdk-only-probe.jsonbytes.in $DURATION.in 2m 05sis refused.Do not dispatch Build release linux from this PR. Eng Convt squash-merges when CI is green and redispatches that workflow.
Merge Danger
Door: two-way.
Blast radius: Linux source-archive receipt
third-party/linux-source-scope/remove-sdk-only-probe.jsononly. Adds unit tests underscripts/release. Does not change package payloads, compare.py, or published v0.2.0 assets.