Case B - NAK-driven repair cascading into the forward pass schedule
A transaction falls behind on repairs and competes with the plan for future passes. Two ways it can end. constructed
The setup
Ground plans out roughly 10 passes ahead, based on how much data fits in each one. If a pass loses some data and needs repair (a NAK - "please resend this"), that repair has to compete for space in a schedule that was already made assuming nothing would go wrong. Eventually, for any one transaction stuck in this backlog, there are exactly two ways it can end - both shown below.
Outcome 1 - Give up: Cancel
This is a manual decision only - there's no autonomous auto-Cancel (that's deferred pending team discussion). Hitting the NAK Limit doesn't trigger Cancel by itself; it only raises an alert. The operator, working from PPS (a NAK backlog directly competes with PPS's own forward pass planning, so it's the natural place ops already looks), reviews the backlog PLDP surfaces - retry count, outstanding gap, elapsed passes - and decides. From PLDP's side this arrives as an abstract "Cancel Tx X" event/API call, not a CFDP-aware exchange - PLDP doesn't need to know the decision came from PPS specifically. Once decided, a Cancel.request is issued. ("Cancel" is the actual book term - "abort" doesn't appear anywhere in the spec.)
What actually happens
CFDP lets either entity initiate a cancel, and the two directions use genuinely different message sequences - not just "whoever decides sends the same thing." Since PLDP is the one deciding here (Q19), this uses the receiving-entity-initiated procedure, not the sending-entity one:
- PLDP decides, closes its own copy of the transaction locally, and sends a single Finished (cancel) message straight to the satellite. No EOF(cancel) is involved in this direction at all - that PDU only appears in the opposite (satellite-initiated) flow.
- How the satellite actually finds out: receiving that Finished (cancel) message is the instruction - the spec ties the satellite's own local cancellation directly to receiving it. It isn't told separately or asked to decide anything.
- The satellite replies with a positively-acknowledged ACK (Finished), matching reason code - cancelling doesn't skip the confirmation round-trip, it just needs one PDU + one ACK in this direction, not two.
Rendered from diagram/case_b_cancel.puml (PlantUML)
Outcome 2 - Keep trying: NAK-based repair
Instead of giving up, the receiver just keeps asking for the missing pieces, across however many passes it takes, until the file is fully covered.
What actually happens
- A pass sends the file, but some frames get lost along the way.
- After that pass ends, PLDP notices the gaps once it processes the recording, and sends a NAK listing exactly the missing byte ranges - not the whole file, just what's actually gone.
- That NAK travels the same route as everything else uplink-bound: PLDP → MCS → next S-band window → satellite.
- The satellite resends only the requested ranges. In practice, this often can't happen the very next pass either - that pass's downlink time may already be spoken for by other planned content, so the actual repair can land two or more passes later.
- If something's still missing after that, the cycle repeats - and each repeat sweep re-checks the whole file, not just the newest gap. There's a limit on how many times this is allowed to repeat before a fault fires - but that fault now only raises an alert to PPS, it doesn't automatically trigger Outcome 1 (Cancel). Ops still decides manually either way.
- Once everything's finally accounted for, it closes normally - the same confirmation exchange from Case A, just arriving several passes later than usual.
For the full mechanics of this timer - both the pure concept and how it maps onto PLDP's post-LOS batch processing - see the NAK Timer concept page.
Rendered from diagram/case_b_nak_repair.puml (PlantUML)
"Keep trying" can itself be stood down and resumed
"Keep trying" doesn't have to mean continuously, uninterrupted retrying. Ops (via PPS) can decide to explicitly stand a repair down for a while - Suspend Tx X - if something else needs the pass bandwidth more urgently, then resume it later. This is where two separate NAK stores come in, confirmed via a conversation with PAVI, each solving a different timing gap:
| Store | Bridges | When it applies |
|---|---|---|
| Ground (PLDP) | "gap detected" → "MCS has an uplink window" | Always - the ordinary X-band-down/S-band-up scheduling gap |
| Satellite (onboard, non-volatile) | "NAK arrived" → "Tx is actually resumed" | Only when the Tx is deliberately Suspended when the NAK lands |
Ordinary freeze/thaw (a pass simply ending, not a deliberate stand-down) needs neither store on the satellite side - thaw always happens right when the next contact opens, the same moment uplink becomes possible again, so a NAK sent "at the next window" never actually arrives to a still-frozen Tx. Only a deliberate Suspend creates real exposure to this.
What's spec-mandated vs. PAVI's implementation choice: the spec guarantees the transmission block above, but says nothing about how an inbound NAK PDU arriving during that suspended window actually gets handled - that's a genuine gap the spec leaves open. The non-volatile satellite-side store (confirmed via PAVI) is the implementation choice that fills it - not something the suspension procedures themselves require or even mention.
The full stand-down/resume sequence, worked through
PLDP suspends itself too, immediately, for free - this is the part that actually holds the already-generated NAK. The moment ops decides to stand Tx X down, PLDP invokes Suspend.request locally on its own copy - no uplink needed, purely internal. Per §4.11.2.7(a), this "suspend[s] transmission of NAK PDUs" - the NAK sitting in PLDP's ground store is now blocked from being released, by protocol definition, not by choice. SAT still needs its own separate signal to suspend (the Q7.12 mechanism, which costs a round trip), so there's a brief window where PLDP is already suspended but SAT is still merely frozen - harmless, since PLDP isn't releasing the NAK during it anyway.
Release is tied to the target pass's downlink request, not to when the NAK was generated: when ops later decides "serve this repair in Pass X," that decision is the same moment PPS is already constructing Pass X's downlink request - not two separate events needing separate coordination. PLDP resumes itself locally at that moment (free, immediate; per §4.6.7.3.1(a) this "resume[s] transmission of NAK PDUs"), and hands the now-eligible NAK to MCS bundled with that same downlink request uplink, rather than as a separate transmission.
Two messages, one uplink event, two onboard routes: the NAK PDU (reserved CFDP-uplink APID, straight to the CFDP entity's queue) and the "Resume Tx X" command (ordinary PUS APID, through the command processor to the payload app, which locally invokes Resume.request) can ride the same uplink frame if ready together (ordinary packet-blocking) but take different paths once demuxed onboard by APID. A small race is possible - the NAK could get processed a moment before the Resume command finishes taking effect - but that's exactly what the satellite's NV store is for: a brief, bounded hold, not the open-ended one from before.
Rendered from diagram/case_b_suspend_repair.puml (PlantUML)
How the two outcomes relate
These aren't two competing designs to pick between, the way Case A's batch-vs-pipeline question was. Both have to exist in the same implementation. Outcome 2 (keep trying) is the default behavior; Outcome 1 (Cancel) only happens when ops, via PPS, actively decides to invoke it - either because Outcome 2's NAK Limit fault raised an alert worth acting on, or because ops decides ahead of that limit that the backlog isn't worth it. Hitting the NAK Limit is a prompt to decide, not an automatic trigger - nothing switches from one outcome to the other by itself.