Skip to content

drift/04: differential parity pilot — the twins test each other - #24

Merged
bhelm merged 2 commits into
drift/metafrom
drift/04-differential-harness
Aug 18, 2026
Merged

bhelm merged 2 commits into
drift/metafrom
drift/04-differential-harness

Conversation

@bhelm

@bhelm bhelm commented Aug 18, 2026

Copy link
Copy Markdown
Owner

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 runner = an XCTest case in the existing test target (swift test --filter ParityRunner); @testable import reaches internal functions with zero new public API. Kotlin runner = a JUnit test under android/app/src/test (reaches internal directly). 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.
  • Driver Tools/parity_diff.py (stdlib): generates curated + SplitMix64-seeded cases (checked-in seed; argument tuples materialized including defaults — cases with and without explicit windowSec cover 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.
  • Gradle: parity env passed through to test JVMs; a parity run is never up-to-date-skipped and never served from the build cache (both were real: an unchanged test task silently wrote nothing until gated).

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 — with trimpToStrain green as the control path. Verified end-to-end on this machine with the real Gradle runner: SUMMARY cases=14 diffs=3. Fixing them is drift/05, after which this pilot goes green and a revert makes it red again.

Sabotage + determinism

PARITY_NEGATIVE_SIDE=swift|kotlin mutates 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

  • End-to-end pilot (Swift runner + real Gradle Kotlin runner + driver): 3/3 known diffs, control green, exit 1 as designed.
  • Both negative-side proofs end-to-end with real Gradle.
  • Full suites: Swift 1429 tests / 2 skipped / 0 failures; Android 3977 / 0 failed / 6 skipped (the extra skip per platform is the runner itself without parity env).
  • Driver unit tests 5/5 (ID-mismatch, nonce-mismatch, bit-level, epsilon, non-finite).

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

bhelm and others added 2 commits August 18, 2026 03:40
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant