CDS transport fault taxonomy, chunked live read with adjacency verification, and an asymmetric retry policy
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 35/100
Research direction
Review cds_transport.py, the #5 fakes, and spec §4.3 alongside the linked plan before choosing an implementation slice. Done means both transports share the listed fault hierarchy, stream emits verified-adjacent chunks, passive retries are bounded while excited records do not retry, and the two cds settings are validated.
Written by the indexing model from the issue text.
Description
Spin-out of #32 · Stage C (#11, #12) · spec §4.3.1, §4.3.2, §4.3.3, §4.3.4, §4.3.7.
Covers #32 items 1, 3, 8, 10.
Only one thing in this issue has been observed (see "the weak empirical driver" below). The rest
is architecture for the multi-user, unattended case. Filed now because this is the single most
expensive thing to retrofit in the whole campaign.
1. The fault taxonomy — the highest-value item
cds_transport.py (#11) must define one exception hierarchy, and both AWGNDSTransport and
TwinTransport must raise the same types, so every handler downstream is testable on the #5 fakes:
CDSTransportError (base — catching this alone is enough to stop driving)
TransportUnavailable network error, framebuilder gone #32 items 3, 10
TestpointLost slot cleared by another user/process #32 items 1, 2
TestpointTimeout allocation did not complete #32 item 8
ChannelNotFound pre-flight existence #32 item 7
ChannelNotInjectable slow read-only EPICS as an excitation ch. #32 item 6
DataIntegrityError non-finite / short / drive mismatch #32 item 5
TimingFault start_time, sample count, rate, GPS #32 item 9
If the transports raise bare RuntimeError, every handler added later is a retrofit across the whole
backend. Two standing rules: an unclassified fault still hits the base and therefore still
triggers safe teardown — the default is safe; and a fault with no matching class is a gap in the
taxonomy, not a licence for an ad-hoc handler — add the class.
The taxonomy is designed to absorb faults not listed in #32. Place a new one by answering two
questions: (i) can we get data at all? no → transport; data arrives but is wrong → integrity; data
is fine but the plant never received the drive → hardware-state. (ii) is the channel recorded or a
test point? That decides whether a retry is even meaningful. Worked examples in spec §4.3.4 — a
front-end model restart, an excitation slot taken by another client, ADC/DAC overflow, framebuilder
disk full, a duotone discrepancy, an operator changing a filter-module gain mid-record — all land on
an existing class with no new mechanism.
2. stream is the primitive; fetch is derived
-
stream(channels, duration, chunk_s) -> Iterator[Capture], withfetchconsuming it. - Blocks are verified adjacent — block k+1 begins exactly where k ended — and concatenated.
- The request stays open for the whole record. Per spec §4.3.1, many channels are not recorded
to disk and must be captured live or they are unretrievable; N back-to-backgetdatacalls
would lose samples at every boundary. This is a correctness requirement, not a style choice.
Why chunk at all — strongest reason first
- Fault detection during the record. A single blocking fetch discovers a framebuilder reboot, a
lost test point or a stream underrun hours late — spec §4.2's campaign estimates run to 2.5 h —
and leaves the #16 SIGINT handler nowhere to land. - Bounded framebuilder resource use. The binding constraint is the resources available to the
framebuilder: hardware with less memory, and/or a machine also running other tasks so memory
is shared. Either, or both. - A weak empirical driver, recorded as such. Framebuilders failing to provide long data stretches
has actually been observed — the one #32 item that is not hypothetical. The cause was never
investigated (candidates: a test-point timeout, framebuilder resource limits, a client-side
limitation) and workarounds are commonly used instead. Not authoritative: no numbers, no logs,
no root cause. It supports the two architectural reasons; it is not their basis.
Concatenation is not stitching
| operation | rule |
|---|---|
| concatenation of verified-adjacent blocks | required — this is the continuous record, and it is invisible downstream |
| fabrication — zero-fill, interpolate, resample or realign across a hole | forbidden always: synthetic samples in X or Y is §2.1's failure class |
| gap-tolerant reassembly — analysing two contiguous runs separated by a known GPS gap | disallowed |
This does not weaken §2.1. That section forbids correcting the buffer; adjacency checking only
verifies it. Gap-tolerant reassembly is recorded as considered-and-rejected in spec §4.3.2 so it is
not re-derived: a common phase shift does cancel in the ratio-of-averages, but the period straddling
the seam carries a discontinuity that appears differently in X (a raw drive jump) than in Y (that jump
filtered by the plant), so Y_seam ≠ H·X_seam. Disallowed as policy.
3. Retry policy — asymmetric on two axes
- Passive reads retry — bounded, with backoff, for
TransportUnavailable/TestpointTimeout.
A passive record may also be re-attempted after a gap: it carries no excitation. - Excited records never retry automatically. Re-taking one means re-injecting, which is a new
actuation needing a new approval token under Rule 2 (#17). - A retry never silently extends a record's duration or the campaign's time budget.
4. What TwinTransport must not pretend (#12)
It must raise every type and emit chunked blocks so all of the above is testable off-hardware. But
respect the real hardware/simulation difference rather than papering over it: in the twin, GPS is
instantiated at runtime and each mdl.run() is a fresh evolution, so continuity across records
is meaningless there and re-acquiring a whole stretch is cheap. Neither holds on hardware, where GPS
comes from an antenna (best case) or an NTP server (worst case). A gap within one twin record is
representable — keep running cycles, do not fetch them — and that is what the gap tests should use.
Note also that an NTP-disciplined clock can step backwards, so GPS monotonicity stays a check and
a backwards step is a TimingFault.
Config surface
Minimal, honouring #31's "no new configuration" instinct: only cds.read_chunk_s (validated
<= segment_duration) and cds.passive_read_retries, both with in-code defaults. The chunk-size
default is provisional — per the feasibility gate, no value can be justified without a framebuilder
measurement, and the number belongs to that machine's available resources, not to us.
Campaign: CDS hardware backend · branch feat/cds-hardware-backend
· spec · plan · handoff
Code is deferred until the plan and issues have been reviewed.
- Dominant language
- Python
- Stars
- 0
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from CaltechExperimentalGravity/system_ident
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 15/100
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 35/100
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
All issues in CaltechExperimentalGravity/system_ident
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
foxglove/mcap#1907 · 1 comment ·
Maintainers usually reply within 1 day
-
namespace operations
Difficulty 1/5 Under an hour Newbie friendliness 72/100
EclipseFdn/open-vsx.org#14623 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
developmentseed/titiler-cmr#261 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
andrewyng/openworker#774 ·
Maintainers usually reply within 1 day
-
aggfuncOpen
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
worldbank/blackmarblepy#160 ·