feat: formal verification suite (OpenJML ESC/RAC + JPF) in a separate CI pipeline - #158
Merged
Merged
Conversation
… CI pipeline Add machine-checked formal verification for StreamBuffer, run in a new pipeline (.github/workflows/formal-verification.yml) kept fully separate from the synchronous Publish pipeline and never a required check. Four layers: - OpenJML ESC (deductive proof, Z3): the 14 static sequential-core methods (2 offset/length validators incl. the (off+len)<0 overflow idiom, + 12 trim-decision/arithmetic helpers) are proven against full functional contracts. A proof-count guard fails the job if the verified scope silently shrinks. - OpenJML RAC: the existing JUnit suite runs against RAC-instrumented classes (contracts checked at runtime, violations throw), forking OpenJML's own JVM so the bundled-spec bigint runtime resolves. - jcstress Mode.Termination: four new tests extend deadlock-freedom coverage to every blocking entry point (read(byte[],off,len) phase-2 and the public waitForAtLeast API), each paired with a write and a close wakeup. - JPF (scheduled/dispatch job): exhaustively model-checks the concurrent read/write/close protocol over all enumerated interleavings; local Docker+JDK11 recipe in src/test/jpf/README.md. Specifications live only in src/main/jml/.../StreamBuffer.jml (the .java stays JML-free, spotless-compatible). Behaviour-preserving production changes were needed for the tooling: 12 pure helpers made static (instance-method ESC is undecidable here), read/write logic lifted into private outer methods (OpenJML RAC miscompiles outer-field access from non-static inner classes), and the write validator's null check inlined (nullable_by_default + Objects.requireNonNull leaves an unprovable ESC goal). SpotBugs suppressions added for the false positives this relocation surfaces (safe volatile increments under bufferLock; single-package OPM on public API; a clear constant NPE message). Default pipeline unchanged and green: 288 tests, SpotBugs 0, PIT 100%. ESC 14/14, RAC 277/277, jcstress 7/7, JPF "no errors detected" (~14k states, negative-control-validated oracle). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TU5B8DDtDwKSS6ohSfoz2Y
bernardladenthin
had a problem deploying
to
maven-central
September 12, 2026 23:34 — with
GitHub Actions
Failure
bernardladenthin
had a problem deploying
to
maven-central
September 12, 2026 23:34 — with
GitHub Actions
Failure
bernardladenthin
had a problem deploying
to
startgate
September 12, 2026 23:34 — with
GitHub Actions
Error
RAC instrumentation slows every method by an unbounded factor, so StreamBufferTest's class-level @timeout(20s) is not a meaningful gate under it: the large-allocation test trim_respectsMaxAllocationSize_splitsLargeBuffer passed well under 20s uninstrumented but timed out on the 2-core CI runner while RAC-instrumented (276/277 passed, the one error was a timeout, not a contract violation). Set junit.jupiter.execution.timeout.mode=disabled for the jml-rac profile only; correctness and contract checking are unaffected, only the timing gate is lifted while instrumented. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TU5B8DDtDwKSS6ohSfoz2Y
bernardladenthin
had a problem deploying
to
maven-central
September 12, 2026 23:41 — with
GitHub Actions
Failure
bernardladenthin
had a problem deploying
to
maven-central
September 12, 2026 23:41 — with
GitHub Actions
Failure
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #158 +/- ##
============================================
+ Coverage 96.88% 96.99% +0.10%
- Complexity 94 116 +22
============================================
Files 1 1
Lines 257 266 +9
Branches 33 29 -4
============================================
+ Hits 249 258 +9
Misses 2 2
Partials 6 6 ☔ View full report in Codecov by Harness. |
4 tasks
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.




Summary
StreamBuffer, run in a new, separate pipeline (.github/workflows/formal-verification.yml) kept fully apart from the synchronous Publish pipeline and never a required check (red surfaces on the PR without blocking merges).(off + len) < 0integer-overflow idiom, proven equivalent to the clean bounds condition under Java wrap semantics) and the 12 trim-decision/arithmetic helpers (incl. the ceiling division proven against its multiplicative characterization and the fulldecideTrimExecutiondecision tree). A proof-count guard fails the job if the verified scope silently shrinks.bigintruntime resolves.Mode.Termination: four new tests extend deadlock-freedom to every blocking entry point — the second wait phase ofread(byte[], off, len)and the publicwaitForAtLeastAPI — each paired with awriteand aclosewakeup.src/test/jpf/README.md.src/main/jml/.../StreamBuffer.jml(the.javastays JML-free / spotless-compatible). Behaviour-preserving production changes were required by the tooling and are documented inline and inCLAUDE.md(12 pure helpers madestatic; read/write logic lifted into private outer methods; write validator's null check inlined). SpotBugs suppressions added for the false positives that relocation surfaces (safe volatile increments underbufferLock; single-package OPM on public API; a clear constant NPE message).Test plan
Verified locally: default
mvn spotless:check verifygreen (288 tests, SpotBugs 0), PIT 100% (192/192), ESC 14/14, RAC 277/277, jcstress 7/7, JPF "no errors detected" (~14k states, oracle validated with a negative control).Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_01TU5B8DDtDwKSS6ohSfoz2Y