Repository navigation
drift/04: differential parity pilot — the twins test each other - #24
Merged
Merged
Conversation
The implementations are each other's expected values: the same nonce-stamped JSONL inputs go through a Swift XCTest runner (@testable, no new public API) and a Kotlin JUnit runner, and a stdlib-Python driver compares the outputs — ID sets must match exactly, every line must echo the run nonce, persisted-class values compare bit-for-bit (bitPattern/toRawBits), declared intermediates epsilon-hybrid 1e-9, only finite numbers, value/error distinguished. Pilot functions: rollingRmssd + trimpToStrain. RED PROOF: the pilot reproduces the three known RMSSD divergences (window boundary [t-w,t] vs (t-w,t], per-window vs global cleaning, value rematching) as diffs, with trimpToStrain green as the control path. Side-specific sabotage (PARITY_NEGATIVE_SIDE=swift|kotlin) is reported as exactly the named side; setting it without the input/output paths is a hard error on both runners, not a silent skip. Cases with and without the explicit windowSec argument cover the documented default drift; the Kotlin runner uses the real Kotlin default, not a re-derivation. Swift double-run produces byte-identical output. Honest limit (by design, closed by the coverage ratchet in #17 step 6): the driver proves output equality, not that production code ran — that attestation is the executed-lines coverage proof; until then the sabotage runs and the reproduced known drifts cover the wiring. Part of the drift-control plan in #17 (step 4). Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…17) The parity variables live outside Gradle's task model, so an up-to-date skip or a build-cache hit would silently write nothing; both mechanisms are gated off whenever any parity variable is set. Normal suite runs keep caching as before. Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plan step 4 of #17: the differential harness pilot. With both implementations runnable on one Linux machine (#19), they become each other's expected values — no golden files, no macOS requirement.
Shape
swift test --filter ParityRunner);@testable importreaches internal functions with zero new public API. Kotlin runner = a JUnit test underandroid/app/src/test(reachesinternaldirectly). Both consume the same env contract (PARITY_INPUT/PARITY_OUTPUT/PARITY_NEGATIVE_SIDE), write canonically sorted JSONL, and echo a per-run nonce into every output line.Tools/parity_diff.py(stdlib): generates curated + SplitMix64-seeded cases (checked-in seed; argument tuples materialized including defaults — cases with and without explicitwindowSeccover the documented default drift) and compares outputs: exact ID-set match, nonce echo, bit-for-bit for the exact class (bitPattern/toRawBits), hybrid 1e-9 epsilon for intermediates, finite-only, value/error distinguished.Red proof (the acceptance criterion)
The pilot reproduces the three known RMSSD divergences as diffs — window boundary
[t−w,t]vs(t−w,t], per-window vs global cleaning, value rematching — withtrimpToStraingreen as the control path. Verified end-to-end on this machine with the real Gradle runner:SUMMARY cases=14 diffs=3. Fixing them isdrift/05, after which this pilot goes green and a revert makes it red again.Sabotage + determinism
PARITY_NEGATIVE_SIDE=swift|kotlinmutates one declared probe on exactly the named side; both directions verified — the driver reports precisely that side and nothing else. Setting the variable without the file paths is a hard error on both runners (not a silent skip). The Swift runner produces byte-identical output across runs (SHA-verified).Verification
Honest limit
The driver proves output equality, not that production code executed — a hollow runner echoing fabricated values could pass the comparison. That attestation is exactly the executed-lines coverage proof of the ratchet (#17 step 6); until it lands, the sabotage runs and the reproduced known drifts cover the wiring. (Called out by the independent review; the review's cache-hit and silent-skip findings are fixed in this PR.)
Review
Codex review (read-only, independent): verdict yellow; confirmed clean: runner equivalence on the env contract, no production sources touched, no fabricated expectations in the checked-in cases, real Kotlin defaults used. All three hardening findings (build-cache hit, NEGATIVE_SIDE-only silent skip, UTF-8 decode asymmetry) are fixed and re-verified above; the attestation limit is documented rather than papered over.
Part of the drift-control plan in #17.
🤖 Generated with Claude Code