Skip to content

Open issues, by the harm they do

84 open, sorted into six tiers by the kind of harm each one does rather than by age or label. Most carry no label at all, so this ordering is the triage rather than a view onto one that already existed.

Derived 2026-08-21 by make issues, which reads the live issue list. Nothing re-reads it for you, so treat the date as the age of this page — the tier assignments below are committed in issue-tiers.toml and reviewed like code.

Tier What it means Open
0 Breaks for a user 0
1 A gate that does not gate 15
2 A claim nothing measures 17
3 Measured cost 6
4 Cannot be reached 15
5 Convergence and hygiene 31

1 of them has a pull request open against it; the Status column says which.

Tier 0 — Breaks for a user

Reproducible through an interface someone actually uses — a crash, a race, a link failure, or a stub documenting a signature the extension does not have.

Empty.

Tier 1 — A gate that does not gate

This repo's own doctrine turned on itself: a claim nothing runs is prose. Each is a check that reports green because it cannot see the thing it names — several confirmed by sabotage.

Issue Summary Status
#659 make test can pass against a stale build — no prerequisite on build open
#682 test: §12's blob-determinism check compares in float at 1e-9, so it asserts float-equality not bit-identity open
#692 characterization: the category has no envelope gate and no figure-freshness gate open
#693 gen_jm_pin --check: a version is 'recorded' if any old arrow line names it, so a rollback passes silently open
#696 docs-check and docs-drift-check keep two copies of the generator --check list, and CI only runs one open
#701 make bench skips function-only modules: bench_util_core builds and is never run open
#716 Validation figures and CSVs are gated by nothing — validate-check only compares rendered markdown open
#736 check_doc_face_parity compares Examples/Raises only, so the divergence that shipped was invisible — and lock-detection.md is stale on CarrierNda open
#744 check_lifecycle: verify the phase-9 example too, by having each report cite it open
#780 The gallery has no gate: 21 committed assets are stale, one script is in no target, and make gallery is red open
#847 Phase 4's sabotage rule is stated on three pages and executed by none open
#857 make gallery runs a script the examples gate deliberately skips, so it cannot pass open
#871 check_stimulus_sources: a hand-computed Es/N0 sigma is an invented level convention, and no marker catches it open
#919 libdoppler.a's declared link line is only checked where pthread is a separate library open
#936 check_stimulus_sources: the pulse marker's C branch cannot fire — it is matched per line against a signature clang-format always splits open

Tier 2 — A claim nothing measures

A header, report or design doc asserts a number or a behaviour that no test and no validator establishes. Not wrong — unestablished, which is a quieter problem.

Issue Summary Status
#645 MpskReceiver timing loop: two measured default changes not taken — DTTL for BPSK/QPSK, and bn_timing's knee open
#646 The resamp double-emit fix is pinned at RateSync level only — MpskReceiver, where it was observed, has no regression test open
#652 Matched pulse bank is laid out against the pre-fix resamp accumulator open
#684 test(symsync): the embedded timing NCO never states its rate, and the gate that would catch it never landed open
#689 DSSS test captures inject 3.01 dB less noise than their cn0_dbhz label, and correcting it exposes non-monotonic acquisition open
#711 agc: the header promises level-independent settling, and §6 measured otherwise open
#715 The DTTL-vs-Gardner tradeoff is measured only where DTTL wins: no SNR axis exists anywhere open
#732 carrier_nda: the acquisition contract needs the seeding number (|df| \<= bn/M), and the arm's absolute wall it does not name open
#733 carrier_nda: the half-symbol arm's 1/2 + 1/(M+1) coherent gain does not reproduce open
#734 carrier_nda: the lock statistic's H0 spread is M-independent per look, and is not through the arm open
#751 The DTTL's "degrades faster at low SNR" claim is unmeasured — the RateSync validator adds no noise open
#754 MpskReceiver: false lock (negative lock, correct frequency and timing) at any m_out mpsk.md §8 would not derive — the cost of #644 open
#814 MpskReceiver: six header claims are covered by nothing in either language (F9) open
#830 The MpskReceiver validation report characterises the complex face only — the real face has no Python evidence open
#831 MpskReceiver: state the link and the requirement, derive the loops (mpsk-refactor 4.3) open
#855 The timing rate residual doubles with a carrier offset present, and nothing characterises the coupling open
#932 symsync_lock's published false-alarm rate moves 1.5x with -ffast-math, and its header states a conclusion neither value supports open

Tier 3 — Measured cost

Performance findings with a number attached. Filed, not fixed; each names the measurement that produced it.

Issue Summary Status
#502 Performance: prepare() scales O(n) with users instead of sharing RRC filters open
#845 make coverage's -O0 tree costs 6 minutes, and -O2 takes two bit-exactness tests red under CI's clang 18 open
#890 snr: both _db_series forms are O(nwindow) — they re-scan the window at every sample open
#896 Multi-config C benchmarks charge the clock ramp to whichever config runs first in review (#941)
#898 make coverage: ddc_fn_scaling.py times out, and the more cores you have the worse it gets open
#905 arith: the Q8 shift kernels are slower than their Q15 twins, not faster open

Tier 4 — Cannot be reached

The capability exists in C and no caller can get to it, or it exists and nothing tells anyone it does.

Issue Summary Status
#545 Reading a capture is undiscoverable and undocumented — enriched view over wfm_reader + a guide open
#578 Container UX: pulled image ships no examples — split into a runtime (compose + Python demos) and a build (C/jm consuming projects) image open
#635 Resampler's bank= is a working, undocumented constructor parameter open
#658 AGC: a seed that cannot fire on silence — buy back the acquisition spread open
#661 RateSync reports over-drive but is silent about under-drive open
#668 RateSync.clipped conflates transmitter over-drive with noise-crest clipping open
#725 wfmgen: --detached silently ignores --realtime, while the other two destinations honour it open
#735 carrier_nda_get_nco_freq is unreachable from Python and telemetry — both published frequency views are the same view open
#750 AGC has no signal-presence notion: on a noise floor it applies 59.9 dB and the next burst arrives hot open
#762 Generated PN/Gold sequence kinds are unreachable from any face open
#813 fec: virtual fill (4.4.2 shortened codeblock) is not implemented, so a frame off the 223*I grid has no path through the outer code open
#844 stream: ten public send entry points have ZERO execution — the CI8/CI16/CF32 slice of PUSH/REQ/REP, including the durable JetStream tier open
#865 doppler reads 131.0-B-3; B-6 is current — and it changed the randomiser default open
#940 DopplerChannel per-sample Doppler profile — deferred; the carrier needs the warping step, not a chord open
#942 wfmgen: sources cannot express clock Doppler — scalar + rate with range draws, over a stateful per-source channel open

Tier 5 — Convergence and hygiene

Duplication, stale pins, harness drift, and the long tail. Real, none of it urgent — and the tier that grows when the ones above it are held.

Issue Summary Status
#535 DsssReceiver: derive segments, adopt async's squaring carrier combine open
#568 RFC: Doxygen → docstring derivation — the jm-side plan, and where the F-series fits open
#615 CI: every action is on the node20 generation — bump to the node24 majors open
#630 GitHub Actions: every pin is stale (up to 5 majors), and the Node 20 forcing we rely on is temporary open
#639 CI is make-SSOT for every gate — the drift is all in the plumbing layer open
#648 resamp_execute_ctrl_push is ULP-sensitive: gcc 13 and gcc 15 disagree on the converged lock metric by 0.031 open
#651 Makefile diverges from the shared convention: no PYTEST command variable, and make test runs only ctest open
#655 UBSan alignment ratchet: 821 misaligned member accesses open
#676 Telemetry: an over-long prefix silently aliases two probes onto one id, and the attach reports DP_OK open
#677 C tests: 88 hand-rolled CHECK macros, 9 of which abort at the first failure open
#678 util: no C test harness, and square_clip.c duplicates its own body open
#685 feat(telemetry): attaching a pipeline takes one call per object; the one-call form was written then lost to a redesign open
#694 make gallery: GALLERY_CHARACTERIZATIONS is plural but the recipe only works at n=1 open
#712 make docs-check gives a wall of false broken links when site/ is absent open
#720 clang-tidy: 172 findings block gating at zero — triage, judgement, and config, in that order open
#721 Three helpers are byte-identical across modules; zeropad_1d is the one that will drift open
#730 jm_test.h is deliberately not vendored: a jm 0.58.0+ test scaffold needs converting to dp_test.h open
#756 Retire wfm_synth_mls_poly() in favour of pn_mls_poly() open
#757 The docstring-coverage ratchet is slack in 24 of 26 modules open
#760 The waveform enum tables have three C homes, and the manifest claims one open
#781 mpsk_receiver_performance_demo: a BPSK trial declares lock with a clean constellation and SER 0.27, and .examples-skip's reason names a different failure open
#802 Cleanup plan for the test/measurement layer: a convergence plan, not a deletion plan (measured) open
#853 A frame is a field list and a stage list: fold both framers into one description open
#856 design/bpsk-receiver is superseded by the collapse and the view — triage its design doc, then close it out open
#893 bench: six benchmarks are declared at a level jm was never told about (three below an object, three inside c_deps) open
#894 Certify viterbi as its own object, rather than inside conv open
#900 Audit: what is left to declare, and the capabilities with no Python path open
#906 The function-only modules are benchmarked in C but not in Python open
#922 Two hand-written out= parameters are invisible to the stub they should be published in open
#933 Migrate the four inline LCG streams off scripts/.private-rng-ratchet open
#937 Four validation harnesses hand-roll AWGN instead of calling the library's awgn, and nothing says they shouldn't open

How an issue gets its tier

By asking what goes wrong if it is never fixed, and nothing else. Age does not raise a tier and neither does effort — a one-line fix that stops a crash outranks a week of hygiene. The tiers are deliberately about harm rather than cost, so that the order to work in falls out of the table instead of being argued each time.

make issues fails if an open issue has no tier, or if a tier names an issue that is closed — so this page cannot rot in either direction without saying so.