Open Questions

The unresolved tradeoffs across the framework. Each will be settled during the v0.5 → v1 cycle.

Resolved decisions worth recording

These were considered “open” early in design and have since been resolved. Recorded here so reviewers see the deliberation.

  1. Annotation transport. Resolved, then narrowed. The resolution was a pluggable local_concurrent inference backend over a writable local store, defaulting to direct Gemini with GEMINI_API_KEY, plus driver-owned Vertex Gemini Batch over immutable GCS WebDataset writing create-only JSONL sidecars. Both stores were retired with the legacy record path, and the Vertex Batch route went with them; a Dataproc Serverless batch over a Signal Dataset snapshot is what remains. The supported manual workflow is documented in Generate, then annotate. General multi-provider annotation orchestration is now built and available, reversing the earlier decision to keep it outside the retained product. rfgen annotate submit can route local-HDF5 annotation through any inference client registered under rfgen.inference_clients: a lower-cost hosted OpenAI-compatible endpoint (Together, Groq, Fireworks) or a local/self-hosted model server (Ollama, vLLM, LM Studio) at effectively zero marginal inference cost. This was built to reduce the cost of bulk annotation at approximately 2,000,000-sample scale, where routing every sample through Gemini via the unified runner was prohibitively expensive. See rfgen.annotators for the extension boundary and the annotation configuration schema for the backend and inference fields. Qualification coverage for this backend surface was limited to two recorded combinations, local HDF5 and remote WebDataset; both stores were retired with the legacy record path, so that coverage no longer describes a route this build has. The backend surface itself is built and available; see Annotations.

  2. Plugin discovery and future hub. Resolved: plugins ship a standardized PluginMetadata declaration (Reference / Plugin Metadata). Discovery uses a BaseRegistry abstraction; the default reads Python entry points, and a future hub-style remote registry is a JsonManifestRegistry subclass added later without core changes.

Cross-cutting

  1. Real captures in the loop or pure sim? Default is “sim with HIL validation,” but specific high-value classes (drone OcuSync, real WiSig devices) may need capture-augmented templates.

  2. Spectrogram-domain output? Some downstream models consume spectrograms directly. Generate IQ canonically and emit spectrograms on-demand, or store both?

  3. Public dataset release tiers. Resolved for the first corpus taken to publication. The constraint turned out not to bind it. Its whole generation path is permissive: TorchSig is MIT, Sionna is Apache-2.0, and every base-install runtime dependency is MIT, BSD, or Apache-2.0. The copyleft dependencies sit in optional extras for emitter families that corpus does not use. Nothing published contains third-party data, since every sample is synthesized by rfgen and the external corpus used as a calibration reference is never redistributed. See NOTICE for the attribution and the provenance boundary. A corpus that reaches a copyleft or data-redistributing emitter family still needs its own assessment, so the tiering question remains open for those.

  4. Provider qualification. Direct Gemini is manually gated and excluded from ordinary CI. The bounded qualifications recorded here were taken over local HDF5 and GCS WebDataset, both retired with the legacy record path, so they do not describe a route this build has; the Vertex Batch path went with them. What remains is a Dataproc Serverless batch over a Signal Dataset snapshot, requiring an immutable image and a worker-readable dependency prefix. No qualification establishes semantic quality or fleet reliability; see Annotate an existing dataset.

  5. TorchSig version pinning. v2.1.x is current; v2.x to v3 will likely break. Pin and lock.

Layout (see Reference / Project Layout)

  1. validation/ inside rfgen vs. sibling package rfgen-validate?

  2. presets/ as YAML files inside the package vs. shipped under configs/presets/?

  3. emitters/cellular/ vs. emitters/lte/ + emitters/nr/?

  4. Where do hardware-fingerprint parameters live: per-emitter or in channels/?

Plugin interfaces (see Reference / Plugin Interfaces)

  1. Should BaseEmitter.generate return Spectrogram too?

  2. BaseChannel.apply shape contract: explicit tail length via meta, or always pad?

  3. BaseAnnotator granularity, one annotator per type or one per suite?

  4. Multi-RX LabeledScene.iq shape: (num_rx, 2, N) vs. (2, num_rx, N) vs. complex (num_rx, N).

Config schema (see Reference / Config Schema)

  1. If a shared SNR-range knob returns, should it live on ChannelConfig or SceneConfig? (The shipped ChannelConfig.snr_db_range field is a legacy compatibility placeholder and is not consumed at runtime.)

  2. Per-emitter SNR override. Add EmitterFamilyConfig.snr_db_range_override?

  3. Hydra structured configs (Pydantic-as-source-of-truth) vs. dict-based.

Label schema (see Reference / Label Schema)

  1. Multi-label segmentation as default? Lean: keep single-label default; per-dataset config knob.

  2. Spectrogram precomputed or on-the-fly? Lean: on-the-fly; opt-in flag.

  3. Per-bin SNR map? Lean: per-emitter scalar for v1.

  4. Confidence-tagged unknown nodes for HIL captures? Lean: introduce in v1.1.

Storage (see Reference / Storage Layout)

  1. _shards/shard_index.parquet required or optional?

  2. WebDataset compression: per-record gzip or per-tar zstd?

  3. HDF5 SWMR mode for ongoing writes?