test(gateway): measure qualification wire capacity
Verify Data Plane / gateway (push) Successful in 4m46s
Verify Data Plane / gateway (push) Successful in 4m46s
This commit is contained in:
@@ -940,12 +940,20 @@ func (c *independentGatewayClient) ReceiveFrame(ctx context.Context) (Frame, err
|
||||
}
|
||||
|
||||
func (c *independentGatewayClient) ReceiveMedia(ctx context.Context) ([]byte, error) {
|
||||
return c.receiveMedia(ctx, nil)
|
||||
}
|
||||
|
||||
func (c *independentGatewayClient) receiveMedia(ctx context.Context, observe func(time.Time, int)) ([]byte, error) {
|
||||
for {
|
||||
data, err := c.connection.ReceiveDatagram(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payload, complete, err := c.media.Add(data, time.Now())
|
||||
receivedAt := time.Now()
|
||||
if observe != nil {
|
||||
observe(receivedAt, len(data))
|
||||
}
|
||||
payload, complete, err := c.media.Add(data, receivedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -669,6 +669,117 @@ func TestQualificationLossAndSteppedThroughputBounds(t *testing.T) {
|
||||
profile.Name == "constrained" && len(observation.CapacityStepObservations) != 2 {
|
||||
t.Fatalf("%s observation = %#v", profile.Name, observation)
|
||||
}
|
||||
for _, step := range observation.CapacityStepObservations {
|
||||
t.Logf("%s %d%%: convergence=%s wire_max_5s=%d wire_cap=%d", profile.Name, step.ReductionPercent, step.Convergence, step.MaximumFiveSecond, step.FiveSecondCap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQualificationCapacityStepsMeasurePublicWireDatagrams(t *testing.T) {
|
||||
const packetCount = qualificationImpairmentPacketCount
|
||||
profile := qualificationMediaProfiles()[0]
|
||||
started := time.Date(2026, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
spacing := time.Duration(int64(time.Second) * int64(profile.PacketBytes) * 8 / (profile.BitrateKbps * 1000))
|
||||
stepAt := map[int]time.Time{
|
||||
25: started.Add(time.Duration(packetCount/3) * spacing),
|
||||
50: started.Add(time.Duration(packetCount*2/3) * spacing),
|
||||
}
|
||||
if phase := stepAt[50].Sub(stepAt[25]); phase != 1_571_842_800*time.Nanosecond {
|
||||
t.Fatalf("25%% phase = %s, want exact source-shaped transition", phase)
|
||||
}
|
||||
|
||||
pacer := newFairPacer(qualificationMediaPacerKbps(profile, 0))
|
||||
const flow = "qualification-wire-flow"
|
||||
now := started
|
||||
stalled := false
|
||||
quarterApplied := false
|
||||
halfApplied := false
|
||||
debtBeforeQuarter := time.Duration(0)
|
||||
logicalDeliveries := make([]qualificationDeliverySample, 0, packetCount)
|
||||
type wireSample struct {
|
||||
reserved time.Time
|
||||
delivery qualificationDeliverySample
|
||||
}
|
||||
wireSamples := make([]wireSample, 0, packetCount*2)
|
||||
for index := 0; index < packetCount; index++ {
|
||||
sourceAt := started.Add(time.Duration(index) * spacing)
|
||||
if now.Before(sourceAt) {
|
||||
now = sourceAt
|
||||
}
|
||||
if !stalled && !sourceAt.Before(stepAt[25].Add(-150*time.Millisecond)) {
|
||||
now = now.Add(42 * time.Millisecond)
|
||||
stalled = true
|
||||
}
|
||||
for _, encodedBytes := range []int{1200, 25} {
|
||||
if !quarterApplied && !now.Before(stepAt[25]) {
|
||||
pacer.mu.Lock()
|
||||
debtBeforeQuarter = pacer.flows[flow].debt
|
||||
pacer.mu.Unlock()
|
||||
pacer.setKbps(qualificationMediaPacerKbps(profile, 25))
|
||||
quarterApplied = true
|
||||
}
|
||||
if !halfApplied && !now.Before(stepAt[50]) {
|
||||
pacer.setKbps(qualificationMediaPacerKbps(profile, 50))
|
||||
halfApplied = true
|
||||
}
|
||||
reserved := pacer.reserveAt(now, flow, encodedBytes)
|
||||
if reserved.After(now) {
|
||||
now = reserved
|
||||
}
|
||||
wireSamples = append(wireSamples, wireSample{
|
||||
reserved: reserved,
|
||||
delivery: qualificationDeliverySample{At: now, Bytes: int64(encodedBytes)},
|
||||
})
|
||||
}
|
||||
logicalDeliveries = append(logicalDeliveries, qualificationDeliverySample{At: now, Bytes: 1225})
|
||||
}
|
||||
if !quarterApplied || !halfApplied || debtBeforeQuarter <= 0 || debtBeforeQuarter > nativeApolloVideoQueueLatency-fairPacerMaximumCatchup {
|
||||
t.Fatalf("capacity transition state quarter=%t half=%t debt=%s", quarterApplied, halfApplied, debtBeforeQuarter)
|
||||
}
|
||||
pacer.mu.Lock()
|
||||
remainingDebt := pacer.flows[flow].debt
|
||||
pacer.mu.Unlock()
|
||||
if remainingDebt != 0 {
|
||||
t.Fatalf("remaining debt = %s, want zero", remainingDebt)
|
||||
}
|
||||
t.Logf("wire model: datagrams=%d debt_before_25=%s remaining_debt=%s", len(wireSamples), debtBeforeQuarter, remainingDebt)
|
||||
wireDeliveries := make([]qualificationDeliverySample, len(wireSamples))
|
||||
for index, sample := range wireSamples {
|
||||
if sample.delivery.At.Before(sample.reserved) {
|
||||
t.Fatalf("wire datagram %d delivered at %s before reservation %s", index, sample.delivery.At, sample.reserved)
|
||||
}
|
||||
wireDeliveries[index] = sample.delivery
|
||||
}
|
||||
|
||||
for _, reduction := range []int{25, 50} {
|
||||
wireBytesPerSecond := qualificationMediaPacerKbps(profile, reduction) * 1000 / 8
|
||||
wireAfterStep := qualificationDeliveriesAfter(wireDeliveries, stepAt[reduction])
|
||||
maximum := qualificationMaximumDeliveryBytes(wireAfterStep, 5*time.Second)
|
||||
if maximum > wireBytesPerSecond*5*105/100 {
|
||||
t.Fatalf("%d%% wire five-second maximum = %d, cap = %d", reduction, maximum, wireBytesPerSecond*5*105/100)
|
||||
}
|
||||
payloadBytesPerSecond := profile.BitrateKbps * int64(100-reduction) * 1000 / 100 / 8
|
||||
legacy := qualificationMeasuredConvergence(
|
||||
qualificationDeliveriesAfter(logicalDeliveries, stepAt[reduction]), stepAt[reduction], payloadBytesPerSecond,
|
||||
)
|
||||
if reduction == 25 && legacy != 11*time.Second {
|
||||
t.Fatalf("25%% complete-frame classifier convergence = %s, want 11s sentinel reproduction", legacy)
|
||||
}
|
||||
observation := qualificationCapacityStepObservation(wireDeliveries, stepAt[reduction], profile, reduction)
|
||||
if observation.Convergence > 10*time.Second {
|
||||
for offset := time.Duration(0); offset < 2*time.Second; offset += 250 * time.Millisecond {
|
||||
var bucket int64
|
||||
for _, delivery := range wireAfterStep {
|
||||
if !delivery.At.Before(stepAt[reduction].Add(offset)) && delivery.At.Before(stepAt[reduction].Add(offset+250*time.Millisecond)) {
|
||||
bucket += delivery.Bytes
|
||||
}
|
||||
}
|
||||
t.Logf("%d%% wire bucket %s = %d bytes (%d B/s)", reduction, offset, bucket, bucket*4)
|
||||
}
|
||||
t.Fatalf("%d%% wire convergence = %s sentinel with wire maximum %d under cap %d", reduction, observation.Convergence, maximum, wireBytesPerSecond*5*105/100)
|
||||
}
|
||||
t.Logf("%d%%: payload_target=%d wire_target=%d legacy=%s wire_convergence=%s wire_max_5s=%d wire_cap_105=%d",
|
||||
reduction, payloadBytesPerSecond, wireBytesPerSecond, legacy, observation.Convergence, maximum, wireBytesPerSecond*5*105/100)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
qualificationToolVersion = "versevdi-gateway-qualification/v8"
|
||||
qualificationToolVersion = "versevdi-gateway-qualification/v9"
|
||||
qualificationImpairmentQueuePackets = nativeApolloVideoQueuePackets
|
||||
qualificationImpairmentMaxPackets = 100_000
|
||||
qualificationImpairmentPacketCount = 10_000
|
||||
@@ -1243,9 +1243,13 @@ func (p *qualificationPath) processingDiagnostics(processed int64) qualification
|
||||
}
|
||||
|
||||
func (p *qualificationPath) receivePayload(parent context.Context) ([]byte, error) {
|
||||
return p.receivePayloadObserved(parent, nil)
|
||||
}
|
||||
|
||||
func (p *qualificationPath) receivePayloadObserved(parent context.Context, observe func(time.Time, int)) ([]byte, error) {
|
||||
ctx, cancel := context.WithTimeout(parent, 2*time.Second)
|
||||
defer cancel()
|
||||
return p.client.ReceiveMedia(ctx)
|
||||
return p.client.receiveMedia(ctx, observe)
|
||||
}
|
||||
|
||||
func qualificationSourceVideoPackets(t *testing.T, key []byte, frame uint32, encoded []byte) [][]byte {
|
||||
@@ -1503,6 +1507,7 @@ func runQualificationImpairment(t *testing.T, profile qualificationImpairmentPro
|
||||
beforeProviderDrops := path.session.mediaDrops.Load()
|
||||
beforeSourceUDP := path.sourceUDP.Load()
|
||||
beforePacer := path.server.pacer.reservations.Load()
|
||||
wireDeliveries := make([]qualificationDeliverySample, 0, len(jobs)*2)
|
||||
grace := max(2*profile.RTT+2*profile.Jitter, 2*time.Second)
|
||||
lastTarget := time.Duration(packetCount) * spacing
|
||||
if len(jobs) > 0 {
|
||||
@@ -1522,7 +1527,9 @@ func runQualificationImpairment(t *testing.T, profile qualificationImpairmentPro
|
||||
metrics := beforeMetrics
|
||||
seen := make([]bool, packetCount)
|
||||
for len(result.packets) < len(jobs) {
|
||||
recovered, receiveErr := path.receivePayload(receiveCtx)
|
||||
recovered, receiveErr := path.receivePayloadObserved(receiveCtx, func(receivedAt time.Time, bytes int) {
|
||||
wireDeliveries = append(wireDeliveries, qualificationDeliverySample{At: receivedAt, Bytes: int64(bytes)})
|
||||
})
|
||||
if receiveErr != nil {
|
||||
if errors.Is(receiveErr, context.DeadlineExceeded) || errors.Is(receiveErr, context.Canceled) {
|
||||
break
|
||||
@@ -1595,7 +1602,6 @@ func runQualificationImpairment(t *testing.T, profile qualificationImpairmentPro
|
||||
return qualificationImpairmentObservation{}, received.err
|
||||
}
|
||||
|
||||
var deliveries []qualificationDeliverySample
|
||||
var totalLatency, totalJitter, previousLatency time.Duration
|
||||
previousDelivered := -1
|
||||
for _, packet := range received.packets {
|
||||
@@ -1620,10 +1626,6 @@ func runQualificationImpairment(t *testing.T, profile qualificationImpairmentPro
|
||||
observation.ObservedOutOfOrder++
|
||||
}
|
||||
previousDelivered = packet.index
|
||||
datagrams := (media.PacketBytes + frameV2PayloadSize - 1) / frameV2PayloadSize
|
||||
deliveries = append(deliveries, qualificationDeliverySample{
|
||||
At: packet.deliveredAt, Bytes: int64(media.PacketBytes + datagrams*frameV2HeaderSize),
|
||||
})
|
||||
observation.MaxQueuePackets = max(observation.MaxQueuePackets, packet.queuePackets)
|
||||
}
|
||||
observation.Delivered = len(received.packets)
|
||||
@@ -1712,17 +1714,11 @@ func runQualificationImpairment(t *testing.T, profile qualificationImpairmentPro
|
||||
return qualificationImpairmentObservation{}, err
|
||||
}
|
||||
for _, reduction := range profile.CapacitySteps {
|
||||
bytesPerSecond := media.BitrateKbps * int64(100-reduction) * 1000 / 100 / 8
|
||||
stepDeliveries := qualificationDeliveriesAfter(deliveries, stepAt[reduction])
|
||||
convergence := qualificationMeasuredConvergence(stepDeliveries, stepAt[reduction], bytesPerSecond)
|
||||
maximum := qualificationMaximumDeliveryBytes(stepDeliveries, 5*time.Second)
|
||||
observation.CapacityStepObservations = append(observation.CapacityStepObservations, qualificationCapacityStep{
|
||||
ReductionPercent: reduction, Convergence: convergence,
|
||||
MaximumFiveSecond: maximum, FiveSecondCap: bytesPerSecond * 5,
|
||||
})
|
||||
step := qualificationCapacityStepObservation(wireDeliveries, stepAt[reduction], media, reduction)
|
||||
observation.CapacityStepObservations = append(observation.CapacityStepObservations, step)
|
||||
if packetCount >= qualificationImpairmentPacketCount &&
|
||||
(convergence > 10*time.Second || maximum > bytesPerSecond*5*105/100) {
|
||||
return qualificationImpairmentObservation{}, fmt.Errorf("capacity step %d failed measured convergence=%s five-second=%d", reduction, convergence, maximum)
|
||||
(step.Convergence > 10*time.Second || step.MaximumFiveSecond > step.FiveSecondCap*105/100) {
|
||||
return qualificationImpairmentObservation{}, fmt.Errorf("capacity step %d failed measured convergence=%s five-second=%d", reduction, step.Convergence, step.MaximumFiveSecond)
|
||||
}
|
||||
}
|
||||
if observation.Delivered+observation.Dropped != observation.Sent ||
|
||||
@@ -1733,6 +1729,17 @@ func runQualificationImpairment(t *testing.T, profile qualificationImpairmentPro
|
||||
return observation, nil
|
||||
}
|
||||
|
||||
func qualificationCapacityStepObservation(wireDeliveries []qualificationDeliverySample, start time.Time, media qualificationMediaProfile, reduction int) qualificationCapacityStep {
|
||||
bytesPerSecond := qualificationMediaPacerKbps(media, reduction) * 1000 / 8
|
||||
deliveries := qualificationDeliveriesAfter(wireDeliveries, start)
|
||||
return qualificationCapacityStep{
|
||||
ReductionPercent: reduction,
|
||||
Convergence: qualificationMeasuredConvergence(deliveries, start, bytesPerSecond),
|
||||
MaximumFiveSecond: qualificationMaximumDeliveryBytes(deliveries, 5*time.Second),
|
||||
FiveSecondCap: bytesPerSecond * 5,
|
||||
}
|
||||
}
|
||||
|
||||
func qualificationKnownImpairment(profile qualificationImpairmentProfile) bool {
|
||||
for _, known := range qualificationImpairmentProfiles() {
|
||||
if profile.Name != known.Name || profile.RTT != known.RTT || profile.Jitter != known.Jitter ||
|
||||
@@ -1759,9 +1766,16 @@ func qualificationDeliveriesAfter(deliveries []qualificationDeliverySample, star
|
||||
func qualificationMeasuredConvergence(deliveries []qualificationDeliverySample, start time.Time, targetBytesPerSecond int64) time.Duration {
|
||||
const window = 250 * time.Millisecond
|
||||
const requiredWindows = 4
|
||||
if len(deliveries) == 0 {
|
||||
return 11 * time.Second
|
||||
}
|
||||
windowOrigin := start
|
||||
if deliveries[0].At.After(windowOrigin) {
|
||||
windowOrigin = deliveries[0].At
|
||||
}
|
||||
consecutive := 0
|
||||
for offset := time.Duration(0); offset <= 10*time.Second; offset += window {
|
||||
windowStart := start.Add(offset)
|
||||
windowStart := windowOrigin.Add(offset)
|
||||
var total int64
|
||||
for _, delivery := range deliveries {
|
||||
if !delivery.At.Before(windowStart) && delivery.At.Before(windowStart.Add(window)) {
|
||||
@@ -1772,7 +1786,7 @@ func qualificationMeasuredConvergence(deliveries []qualificationDeliverySample,
|
||||
if rate >= targetBytesPerSecond*90/100 && rate <= targetBytesPerSecond*105/100 {
|
||||
consecutive++
|
||||
if consecutive == requiredWindows {
|
||||
return offset + window
|
||||
return windowStart.Add(window).Sub(start)
|
||||
}
|
||||
} else {
|
||||
consecutive = 0
|
||||
|
||||
@@ -8,7 +8,7 @@ Because the bounded fixture uses loopback rather than a physical 1 Gbps link, v8
|
||||
|
||||
The retained v6 qualification run passed its then-current checks but is superseded because its tight-loop sender contradicted the pinned Apollo schedule. Private Linux runs 123 and 124 remain failed evidence. One local v8 sustained run passed on Darwin, but it is neither Linux proof nor normative Section 7 evidence.
|
||||
|
||||
The later Darwin non-sustained pre-CI invocation was not green and was not retried. Its 1440p120 profile delivered the exact 6,250,000 bytes in 120 frames plus all 6,483 source and warm-up shards with zero drops, but measured 46,973.13 kbps over an implied approximately 1.0644383 seconds and failed the 5% throughput gate. Private Linux full verification/artifact retention and the replacement v8 normative run remain open.
|
||||
The later Darwin non-sustained pre-CI invocation was not green and was not retried. Its 1440p120 profile delivered the exact 6,250,000 bytes in 120 frames plus all 6,483 source and warm-up shards with zero drops, but measured 46,973.13 kbps over an implied approximately 1.0644383 seconds and failed the 5% throughput gate. Private Linux full verification/artifact retention and the replacement v9 normative run remain open.
|
||||
|
||||
Private Linux run 125 at the frozen v8 harness head is retained as failed evidence. Its exact 33-datagram gap between successful fixture writes and production `MediaIngress` equaled the Linux socket's 33 measured kernel UDP drops. The complete-frame queue, fair pacer, QUIC fragmentation, and public decoder were downstream and did not account for the loss.
|
||||
|
||||
@@ -16,6 +16,10 @@ The one authorized v8 Section 7 invocation at production candidate `55afea72a148
|
||||
|
||||
The production fair pacer previously limited instantaneous recovery to 5 ms by moving an overdue flow's schedule to `now-5ms`, but silently discarded every additional valid scheduling interval. Repeated host stalls therefore accumulated complete frames in the existing provider queue until its 250 ms residence horizon correctly expired one. The repair keeps the 5 ms instantaneous ceiling, carries only the remaining debt up to that existing horizon, and shortens later nominal intervals by at most one twenty-first. That 20/21 interval is exactly 5% above nominal rate; once the debt reaches zero, the flow returns to its unchanged nominal interval. Per-flow debt and the shared nominal fair-share calculation preserve the existing eight-flow fairness and rolling aggregate cap through the existing 25% and 50% capacity changes.
|
||||
|
||||
Private Linux run 127/job 481 at exact source `122080ab342d20585d9a45db0017337b9ece570a` is retained as failed evidence. `TestQualificationLossAndSteppedThroughputBounds` reported the 25% step's 11-second convergence sentinel and a 5,207,475-byte five-second maximum. No artifact was uploaded and the run was not retried. The retained log `/private/tmp/versevdi-gitea-run-127-job-481.log` has SHA-256 `2b368413d4b0e954c64ba6f6dcefb1e165166d773b6d8f84ee372bc2c92ff5f1`. The failure exposed a measurement-unit defect: capacity samples were emitted only after complete logical-payload reassembly and were compared with a payload-derived target even though the pacer reserves encoded public datagram bytes. It did not establish a production pacer defect, and `122080ab` is superseded as a final source candidate.
|
||||
|
||||
Qualification v9 observes every raw public QUIC datagram immediately after the independent client's `ReceiveDatagram` returns and before the existing decoder/reassembler. Capacity convergence and rolling five-second maxima use those monotonic receive times and encoded lengths. Their target bytes per second and five-second cap derive from `qualificationMediaPacerKbps(profile, reduction) * 1000 / 8`. Complete logical-payload observations remain separate and continue to own payload integrity, loss, reorder, latency, throughput, and queue assertions. The first public delivery at or after a step anchors the four consecutive 250 ms windows so an arbitrary control-plane timestamp cannot split the first observed datagram pair. The delivery-after-step boundary, 90%-105% window bounds, ten-second convergence ceiling, and rolling-five-second 105% gate are unchanged.
|
||||
|
||||
The ingress repair follows reviewed behavior rather than copying implementation source:
|
||||
|
||||
- Apollo `adc5c5a0bd80831ce495434bb16aee2cd4175fb8`, GPL-3.0, `src/stream.cpp:1463-1474,1573-1627`, supplies the 80%-of-1-Gbps raw-block pacing, 64-KiB/64-packet batch cap, and cross-frame send schedule used by the fixture.
|
||||
@@ -42,6 +46,7 @@ The native provider therefore requests `2,048 * 1,072 = 2,195,456` bytes with `S
|
||||
- Keep the existing path/impairment/resource driver and change its unit from datagram payload to complete frame.
|
||||
- Keep video decrypt/FEC single-threaded; only the bounded connected-socket drain is separated so crypto stalls cannot become unexplained kernel loss.
|
||||
- Preserve valid scheduling debt after bounded host stalls instead of converting it into provider-queue residence; repay it within the existing fair pacer without a new queue, interface, or configured headroom.
|
||||
- Classify constrained-capacity evidence from actual public datagram observations and configured wire capacity; do not infer transport timing from completed logical frames.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ Private Linux run 125 then demonstrated a separate production-ingress defect aft
|
||||
|
||||
The consumed v8 Section 7 attempt at `55afea72` subsequently failed after accumulated host scheduling delays exposed the production pacer's discarded schedule debt beyond its 5 ms instantaneous catch-up allowance. The retained partial evidence remains failed and supersedes `55afea72` as a final executable candidate.
|
||||
|
||||
Private Linux run 127/job 481 at exact source `122080ab342d20585d9a45db0017337b9ece570a` then failed `TestQualificationLossAndSteppedThroughputBounds`: the 25% capacity step reported the 11-second convergence sentinel and 5,207,475 bytes in the measured five-second window. The run produced no artifact and was not retried. Its retained log is `/private/tmp/versevdi-gitea-run-127-job-481.log`, SHA-256 `2b368413d4b0e954c64ba6f6dcefb1e165166d773b6d8f84ee372bc2c92ff5f1`; `122080ab` is superseded as a final source candidate.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Generate deterministic variable-size encoded frame units at the named frame rates and target bitrates, including bounded keyframes.
|
||||
@@ -15,6 +17,7 @@ The consumed v8 Section 7 attempt at `55afea72` subsequently failed after accumu
|
||||
- Assert frame count/rate, bitrate, exact bytes and boundaries, clean loss attribution, latency, and resource bounds.
|
||||
- Decouple native video socket draining from the single decrypt/FEC processor with a fixed provider-scoped receive pool and request the source-backed video receive-buffer size.
|
||||
- Retain bounded valid per-flow pacing debt after a host stall and repay it at no more than 5% above nominal fair share.
|
||||
- Measure capacity convergence and rolling caps from each raw public QUIC datagram's observed length and receive time while retaining completed logical-payload observations for integrity and traversal results.
|
||||
- Keep short smoke tests separate and leave all prior normative artifacts unchanged.
|
||||
|
||||
## Capabilities
|
||||
|
||||
+6
@@ -9,6 +9,8 @@ Native Apollo video ingress SHALL request a 2,195,456-byte socket receive buffer
|
||||
|
||||
The production fair pacer SHALL retain its 5 ms instantaneous catch-up ceiling. When a flow resumes later than that ceiling, it SHALL carry the remaining valid schedule debt only within the existing 250 ms provider-queue horizon and SHALL repay that debt using an interval no shorter than 20/21 of its nominal equal-tier fair-share interval. It SHALL return to the nominal interval when the debt is repaid. Simultaneous debt across eight equal-tier flows and the existing 25% and 50% capacity changes SHALL preserve the existing share-error contract and SHALL NOT exceed 105% of configured aggregate capacity in any rolling five-second window.
|
||||
|
||||
Capacity-step convergence and rolling-cap evidence SHALL use the monotonic receive time and encoded length of every raw public QUIC datagram observed immediately after the independent client's `ReceiveDatagram` returns and before decode or reassembly. For each reduction, target bytes per second and the five-second cap SHALL derive from the configured public-wire rate, `qualificationMediaPacerKbps(profile, reduction) * 1000 / 8`. Completed logical-payload observations SHALL remain separate and SHALL continue to measure payload integrity, loss, reorder, latency, throughput, and queue behavior. A capacity step SHALL include only delivery observations at or after its recorded transition, anchor measurement windows at the first such public delivery, require four consecutive 250 ms windows between 90% and 105% of its target, converge within ten seconds, and remain at or below 105% in every rolling five-second window.
|
||||
|
||||
#### Scenario: Healthy fixed profile
|
||||
- **WHEN** a frozen candidate runs one fixed profile for the normative duration in the isolated qualification command
|
||||
- **THEN** the harness emits compressed raw frame/path and gateway-process resource samples plus a summary tied to the exact command, CPU scope, timing-overhead method, topology, source commit, immutable Protocol version, environment, and payload hash
|
||||
@@ -32,3 +34,7 @@ The production fair pacer SHALL retain its 5 ms instantaneous catch-up ceiling.
|
||||
#### Scenario: Repeated media-loop host stalls
|
||||
- **WHEN** three approximately 95 ms scheduling debts are introduced at separated completed-public-frame barriers while source recovery continues
|
||||
- **THEN** the pacer limits instantaneous catch-up to 5 ms, repays each remaining debt at no more than 5% above nominal fair share, preserves every frame in exact order and bytes without provider or gateway drops, stays within the existing queue bounds, and closes cleanly on cancellation
|
||||
|
||||
#### Scenario: Capacity measurement crosses a short transition phase
|
||||
- **WHEN** a constrained 1080p flow carries nonzero bounded debt through the approximately 1.572-second 25% phase before the 50% transition
|
||||
- **THEN** convergence and rolling-cap checks use the observed 1,200-byte and 25-byte public datagrams against the configured wire targets, while the separately retained completed-payload observations cannot substitute for transport delivery timing
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
- [x] 5.1 Retain the v6 qualification attempt and mark its passing result superseded by the tight-loop source defect
|
||||
- [x] 5.2 Implement v8 post-first-write, non-collapsing complete-frame UDP pacing with persistent cross-frame carry and verify the focused, race, short-resource, and cross-platform compile checks that passed
|
||||
- [x] 5.3 Preserve private Linux runs 123 and 124 as failed evidence, the passing local v8 Darwin sustained run as non-Linux and non-normative, and the un-retried failed Darwin non-sustained pre-CI invocation with its exact throughput evidence
|
||||
- [ ] 5.4 Run private Linux full verification and retain deterministic Linux artifacts for the frozen v8 harness and video-ingress descendant
|
||||
- [ ] 5.5 Run one separately approved replacement v8 normative Section 7 qualification
|
||||
- [ ] 5.4 Run private Linux full verification and retain deterministic Linux artifacts for the frozen v9 measurement descendant
|
||||
- [ ] 5.5 Run one separately approved replacement v9 normative Section 7 qualification
|
||||
|
||||
## 6. Native video ingress remediation
|
||||
|
||||
@@ -38,3 +38,8 @@
|
||||
- [x] 7.2 Reproduce repeated host-stall queue expiry through the public native path and add bounded one-flow/eight-flow debt, fairness, rolling-cap, and capacity-step regressions
|
||||
- [x] 7.3 Retain the 5 ms instantaneous ceiling, carry valid debt within the 250 ms queue horizon, and repay it at no more than 5% above nominal fair share
|
||||
- [ ] 7.4 Freeze and verify a new executable candidate on private Linux before any separately authorized replacement normative run
|
||||
|
||||
## 8. Public-wire capacity measurement correction
|
||||
|
||||
- [x] 8.1 Preserve run 127/job 481 at `122080ab` as failed evidence with its exact log hash, no artifact, and no retry
|
||||
- [x] 8.2 Record raw independent-client QUIC datagram lengths/times and derive v9 capacity convergence and caps from configured wire rate while keeping logical payload observations separate
|
||||
|
||||
Reference in New Issue
Block a user