Skip to content

feat(network): 802.1Qbv GCL synthesis baseline (REQ-TSN-SYNTH-QBV-BASE-001)#290

Merged
avrabe merged 1 commit into
mainfrom
feat/v0.20.0-qbv-synth
Jun 15, 2026
Merged

feat(network): 802.1Qbv GCL synthesis baseline (REQ-TSN-SYNTH-QBV-BASE-001)#290
avrabe merged 1 commit into
mainfrom
feat/v0.20.0-qbv-synth

Conversation

@avrabe

@avrabe avrabe commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What

First cut of 802.1Qbv Gate Control List (GCL) synthesis — the inverse of the existing TAS checker (tas_residual_service). Given a per-egress-port set of class demands (arrival curve + NC deadline), synthesize_gcl produces a GateSchedule whose windows tile [0, cycle_ps) such that every class's residual-service curve meets its deadline.

This implements REQ-TSN-SYNTH-QBV-BASE-001 (the bandwidth baseline), a deliberate precursor split from REQ-TSN-SYNTH-QBV-001 — mirroring the REQ-NC-PLP-CONVERGE-001 → REQ-NC-PLP-003 precedent.

The synthesis model (baseline)

Each class K gets one contiguous open window (mask = 1<<cos) of duration d_K; the leftover becomes a single closed guard window (mask = 0). With one window per class:

  • T_K (worst-case latency) = cycle − d_K
  • R_K (open-fraction rate) = link · d_K / cycle

Both are independent of window placement, so delay(d_K) = (cycle − d_K) + σ_K/R_K is strictly decreasing in d_K. That gives a unique minimal feasible d_K via binary search; the only inter-class coupling is the budget Σ d_K ≤ cycle.

Window order/placement is a provable no-op on these bounds — which is precisely why the paper's lever (window splitting, arXiv:2407.00987) is scoped out into REQ-TSN-SYNTH-QBV-001 (deferred to v0.21.0), not claimed here.

Oracle (written first, red→green)

The existing checker is a free, exact oracle for the synthesizer's output. Every test round-trips:

synthesize_gcl → to_gcl_blob → GateSchedule::parse (zero error)
              → tas_residual_service per class → delay_bound ≤ deadline

The synthesizer is self-certifying: the binary-search predicate AND a final pass both use the real tas_residual_service + delay_bound (no parallel closed-form), and synthesize_gcl re-parses its own emitted blob before returning — so integer-nanosecond rounding cannot diverge from the analyzer's bound. GateSchedule::parse consumes nanoseconds, so windows are sized in whole ns.

6 new tests: multiclass round-trip + all-deadlines-met, tighter-deadline-widens-window (monotonicity), leftover→closed guard, rejects sub-transmission-delay class, rejects oversubscribed port, input validation.

Falsification statement

If synthesize_gcl returns a GateSchedule, then for every input ClassDemand the network-calculus delay_bound of that class under the returned schedule (as computed by the independent tas_residual_service analyzer) is ≤ its deadline_ps; otherwise it returns a typed GclSynthError. A schedule that the analyzer rejects, or a class that exceeds its deadline, falsifies this.

Scope notes (honest to the primitive)

  • synthesize_gcl is a library primitive with a unit oracle; there is no AADL→synth→export path yet. The DEC-TSN-OSS-001 competitive wedge is not demonstrated until that bridge exists (a separate follow-up; extract_network_graph gives topology+rates, not per-class arrivals with per-hop deadline budgets).
  • No new dependency — sits entirely on the existing curves/NC machinery.

Gates (local)

  • cargo test -p spar-network — 144 pass (6 synth + 127 lib + 11 nc_validation)
  • cargo clippy -p spar-network --all-targets -- -D warnings — clean
  • cargo fmt -p spar-network -- --check — clean
  • cargo build -p spar-network --no-default-features — OK

🤖 Generated with Claude Code

…E-001)

Synthesize a TAS gate-control list for one egress port — the inverse of
the existing TAS checker (REQ-TSN-002). Each class gets one contiguous
open window (mask=1<<cos) sized by a monotone binary search so its
tas_residual_service curve meets its per-hop deadline under the EXACT
network-calculus delay_bound; leftover cycle time becomes a closed guard
window (mask=0). The search predicate and a final pass both run the real
checker (tas_residual_service + delay_bound) on the synthesizer's own
output, and synthesize_gcl re-parses its emitted GCL blob before
returning — self-certifying, so a future change that breaks soundness
fails construction, not just the test.

Adds ClassDemand, GclSynthError (NoDemands / CycleNotWholeNanos /
DuplicateClass / ClassInfeasible / Oversubscribed / SelfCheck), and
GateSchedule::to_gcl_blob. Window durations are nanosecond-quantized to
match GateSchedule::parse (which consumes ns).

Scope: this is the BANDWIDTH baseline. With one window per class the
worst-case gate latency is cycle − duration, independent of window
placement — window order is a provable no-op on the bounds. Closing the
residual gap needs window SPLITTING, which is the re-scoped
REQ-TSN-SYNTH-QBV-001 (moved to v0.21.0, arXiv:2407.00987's actual
contribution). Mirrors the REQ-NC-PLP-CONVERGE-001 → REQ-NC-PLP-003
precursor split.

Oracle TEST-TSN-SYNTH-QBV-BASE: round-trip + per-class deadline,
monotone window widening, guard window, infeasibility/oversubscription,
input validation (6 tests). No new dependency.

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

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.07692% with 31 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/spar-network/src/tsn.rs 88.07% 31 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown

Rivet verification gate

20/20 passed

count
Passed 20
Failed 0
Skipped (no steps) 0

Filter: (and (= type "feature") (or (has-tag "v093") (has-tag "v0100")))

Failed artifacts

(none)

Updated automatically by tools/post_verification_comment.py. Source of truth: artifacts/verification.yaml.

@avrabe avrabe merged commit ff2c023 into main Jun 15, 2026
17 of 18 checks passed
@avrabe avrabe deleted the feat/v0.20.0-qbv-synth branch June 15, 2026 04:23
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