Skip to content

Ported CUBIC, DRR, and WFQ checkers onto the generic TraceSpec interface.#99

Merged
baochunli merged 3 commits into
mainfrom
tracespec-cubic-drr-wfq
Jul 4, 2026
Merged

Ported CUBIC, DRR, and WFQ checkers onto the generic TraceSpec interface.#99
baochunli merged 3 commits into
mainfrom
tracespec-cubic-drr-wfq

Conversation

@baochunli

Copy link
Copy Markdown
Collaborator

Summary

Ports the remaining three LeanGuard checkers — CUBIC, DRR, and WFQ — onto the generic LeanGuard.Shared.TraceSpec interface, matching AQM, PFC, and DCQCN (the latter merged in #98). This closes the mechanization item called out in the paper's conclusion — "extending per-protocol mechanization from AQM, PFC, and DCQCN to the CUBIC, WFQ, and DRR checkers" — so all six protocol checkers now share the same replay interface and delegate their soundness/preservation lemmas to the once-and-for-all generic proofs in TraceSpec.lean.

This is a behavior-preserving structural refactor, not new proof work. Each checker's hand-rolled recursive go loop is replaced by a ReplayState/TraceSpec instantiation. The hard semantic content — step (transition semantics), recordCover (coverage), key, and canonicalizeRows ordering — is reused unchanged. No protocol instantiates the preservation lemma with a concrete invariant, so there are no bespoke proofs to discharge; a green lake build is the proof check (the theorems elaborate at build time).

Commits (one per protocol)

  1. Port CUBICstep takes Row directly; recordCover(cov, r). Simplest case.
  2. Port DRRstep fed via toEvent; recordCover(cov, g, r) reads the pre-step Global.
  3. Port WFQ (+ shared Coverage.lean) — see design note below.

All three follow the DCQCN ReplayState { g, lastKey } template rather than the AQM/PFC no-wrapper template, because each currently performs a per-row keyLt "global key went backwards" monotonicity check; that check is preserved inside stepRow.

Design note: WFQ's observer accumulator → CoverageState

WFQ's coverage observer threads a distinct-class accumulator (seenClasses) that lived outside both Global and CoverageState, returning CoverageState × List Nat. The generic observer signature CoverageState → State → Row → CoverageState has no room for it. Rather than putting coverage bookkeeping into the trusted replay state, this PR adds a generic seen : Std.HashSet Nat scratch field to the shared CoverageState (plus covSeen and a covMerge union). This keeps WFQ's observeCoverage self-contained and its stepRow uniform with the other five checkers, and preserves the observation-vs-replay separation that replayWithObserverM_agrees formalizes.

The field is never serialized (covList/CoverageReport.toJson only emit points/counts), so coverage reports and golden fixtures are unchanged, and the cross-layer aqm_dcqcn_check merge is unaffected (AQM/DCQCN leave seen empty). class_count_ge_2 now gates on cov.seen.size >= 2, equivalent to the old distinct-list length; the now-dead listContains helper is removed.

Preserved (no external change)

checkRowsWithCoverage / checkRows keep their signatures, so CubicMain / DrrMain / WfqMain, the composite AqmDcqcnMain, lakefile.lean, CI, configs/ci/*.toml, and all fixtures/golden files are untouched.

Verification

  • Build: lake build of all 7 checkers — green, no warnings / sorry / errors. Since Coverage.lean is shared, this recompiles every protocol + aqm_dcqcn_check, and elaborates all soundness/preservation proofs.
  • Golden fixtures: CUBIC 5/5 (behavior unchanged), AQM 38/38 + AQM coverage 8/8 (regression check for the shared Coverage.lean edit; confirms seen is not leaked into reports).
  • Conformance matrix (leanguard-run drives the Days simulator, then runs the checkers on emitted traces — the only end-to-end coverage DRR/WFQ have):
    • leanguard_cubic.tomlaccept: true (aqm_check, cubic_check)
    • leanguard_drr.tomlaccept: true (aqm_check, drr_check)
    • leanguard_wfq.tomlaccept: true (aqm_check, wfq_check)

Out of scope (possible follow-ups)

  • Dedicated golden fixtures + run-drr-fixtures.sh / run-wfq-fixtures.sh + CI steps for DRR/WFQ (they have none today; only the conformance matrix exercises them).
  • Harmonizing the keyLt check across all six checkers (AQM/PFC dropped it and rely on canonicalizeRows sorting alone).
  • Proving concrete protocol invariants via replayM_preserves (a much larger effort that no existing checker attempts).

🤖 Generated with Claude Code

baochunli and others added 3 commits July 3, 2026 22:57
Replace the hand-rolled checkRowsWithCoverage replay loop with a ReplayState wrapper and a TraceSpec instantiation, mirroring the DCQCN port (#98). The existing step/recordCover/key/canonicalizeRows semantics are reused unchanged, and the per-row global-key monotonicity check is preserved inside stepRow. Soundness and preservation lemmas delegate to the generic TraceSpec proofs, so no new proof obligations are introduced; the build elaborates them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the checkRowsWithCoverage replay loop with a ReplayState wrapper and a TraceSpec instantiation, following the DCQCN template. step is fed via toEvent and recordCover reads the pre-step Global, exactly as before; the global-key monotonicity check moves into stepRow. Soundness/preservation lemmas delegate to the generic TraceSpec proofs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the checkRowsWithCoverage replay loop with a ReplayState wrapper and a TraceSpec instantiation. WFQ's coverage observer previously threaded a distinct-class accumulator (seenClasses) that lived outside both Global and CoverageState. To keep observeCoverage self-contained and uniform with the other five checkers, thread it through a generic 'seen : Std.HashSet Nat' scratch field added to the shared CoverageState (with covSeen and a covMerge union). The field is never serialized, so coverage reports and golden fixtures are unchanged. class_count_ge_2 now gates on cov.seen.size >= 2, equivalent to the old distinct-list length; the now-dead listContains helper is removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@baochunli baochunli changed the title Port CUBIC, DRR, and WFQ checkers onto the generic TraceSpec interface Ported CUBIC, DRR, and WFQ checkers onto the generic TraceSpec interface. Jul 4, 2026
@baochunli
baochunli merged commit 1b07250 into main Jul 4, 2026
8 checks passed
@baochunli
baochunli deleted the tracespec-cubic-drr-wfq branch July 4, 2026 03:33
baochunli added a commit that referenced this pull request Jul 6, 2026
* Add DRR and WFQ golden fixtures and wire them into CI

The lean-fixtures CI job built drr_check and wfq_check but never ran them on golden fixtures — only AQM and CUBIC had fixture scripts, so DRR/WFQ were exercised solely by the accept-only conformance matrix. In particular WFQ's class_count_ge_2 coverpoint (the ported `seen` accumulator path from #99) was not golden-tested anywhere.

Add fixtures/drr and fixtures/wfq mirroring the CUBIC/AQM layout: an accept trace (captured verbatim from the CI conformance run) plus reject cases per checker, and --coverage-out golden fixtures. A hand-verified 2-class WFQ trace (simulator-generated, accept-by-construction) golden-tests class_count_ge_2. All .expected/.coverage.expected files are snapshots of real checker runs, not hand-written. Add run-{drr,wfq}[-coverage]-fixtures.sh (clones of the cubic/aqm runners) and four CI steps. No Lean source changes; checker behavior is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Harden coverage fixture runners against restrictive TMPDIR

Use `mktemp -p .` (repo-local temp file) instead of the default
`mktemp`, which honors $TMPDIR and fails with "Operation not
permitted" under sandboxes that deny writes to the system temp dir.
Applied to all three coverage runners (aqm/drr/wfq) for consistency.
Works on both BSD (macOS) and GNU (CI) mktemp; temp files are removed
each iteration and never land in the repo tree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <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