020c(gui): Generate scenario button — sidecar-only output + CLI parity #35

Merged
ykp merged 1 commit from feat/020c-gui-generate-scenario into main 2026-09-29 15:12:48 +02:00
Owner

Implements backlog step 020c (docs/backlog/020c-gui-generate-scenario.md, now archived to docs/done/ with outcome). Depends on 020a (merged, #32) and 020b (merged, #33).

What it adds

A Generate scenario button in the bottom controls row (left of Generate): runs the step-014 pre-flight (can_generate gate -> scenario_from_model -> validate(), identical status messages), draws the channels (draw_channels so resolved_seed and all drawn values are recorded), then serializes only the scenario JSON to a .scenario.json file chosen via save dialog (initialfile derived from the output-path stem). Users get a reproducible spec for gengnss scenario FILE -o out.i16 or a receiver harness without generating IQ first.

  • Sidecar content: scenario.to_json() + drawn channel entries (incl. fdma_channel) + generated_by, via the new scenario_sidecar_document helper in controllers.py — same shape as generate_to_file's artifact minus the IQ-run-only fields (feasibility verdicts are recomputed by the CLI; peak/samples belong to the IQ run), per the work order.
  • Disabled while a generation job runs (same lock as the 020b buttons).

Tests (tests/test_gui_generate_scenario.py)

  • Headless: sidecar round trip (GPS x2 + GLONASS :chan + power offset; resolved_seed recorded; drawn channels present); CLI parity — cli_main(["scenario", gui_file, "--output", a.i16]) produces byte-identical IQ to in-process generate_to_file of the same scenario (same seed); invalid-model refusal documented at model level.
  • gui-marked: full handler flow through the real UI path (checkbox + spec entry), status line scenario written: ... (2 signals, seed ...), dialog initialfile, lock behavior.

Verification

  • ruff check src/gengnss tests clean; pytest: 201 passed, 6 skipped (gui-marked skip headless; run in CI with a display).
  • CI: fresh-checkout workflow in effect since #34; this PR's run exercises all three legs.

Backlog updates (in this PR)

  • docs/backlog/000-overview.md: 020a/020b/020c rows marked done (020a -> PR #32, 020b -> PR #33).
  • Work orders 020a/020b/020c archived to docs/done/ with outcome notes.

Remaining backlog items (020b untouched items beyond the merged ones are none — next candidates are the Remaining list: sig front-end wiring, BeiDou B2b, spec 7.2 external cross-check).

Implements backlog step **020c** (`docs/backlog/020c-gui-generate-scenario.md`, now archived to `docs/done/` with outcome). Depends on 020a (merged, #32) and 020b (merged, #33). ## What it adds A **Generate scenario** button in the bottom controls row (left of Generate): runs the step-014 pre-flight (`can_generate` gate -> `scenario_from_model` -> `validate()`, identical status messages), draws the channels (`draw_channels` so `resolved_seed` and all drawn values are recorded), then serializes **only the scenario JSON** to a `.scenario.json` file chosen via save dialog (`initialfile` derived from the output-path stem). Users get a reproducible spec for `gengnss scenario FILE -o out.i16` or a receiver harness without generating IQ first. - Sidecar content: `scenario.to_json()` + drawn channel entries (incl. `fdma_channel`) + `generated_by`, via the new `scenario_sidecar_document` helper in controllers.py — same shape as `generate_to_file`'s artifact minus the IQ-run-only fields (`feasibility` verdicts are recomputed by the CLI; `peak`/`samples` belong to the IQ run), per the work order. - Disabled while a generation job runs (same lock as the 020b buttons). ## Tests (`tests/test_gui_generate_scenario.py`) - **Headless:** sidecar round trip (GPS x2 + GLONASS `:chan` + power offset; `resolved_seed` recorded; drawn channels present); **CLI parity** — `cli_main(["scenario", gui_file, "--output", a.i16])` produces **byte-identical IQ** to in-process `generate_to_file` of the same scenario (same seed); invalid-model refusal documented at model level. - **gui-marked:** full handler flow through the real UI path (checkbox + spec entry), status line `scenario written: ... (2 signals, seed ...)`, dialog `initialfile`, lock behavior. ## Verification - `ruff check src/gengnss tests` clean; `pytest`: **201 passed, 6 skipped** (gui-marked skip headless; run in CI with a display). - CI: fresh-checkout workflow in effect since #34; this PR's run exercises all three legs. ## Backlog updates (in this PR) - `docs/backlog/000-overview.md`: 020a/020b/020c rows marked **done** (020a -> PR #32, 020b -> PR #33). - Work orders 020a/020b/020c archived to `docs/done/` with outcome notes. Remaining backlog items (020b untouched items beyond the merged ones are none — next candidates are the Remaining list: `sig` front-end wiring, BeiDou B2b, spec 7.2 external cross-check).
020c(gui): Generate scenario button — sidecar-only output + CLI parity
All checks were successful
ci / test (3.14) (push) Successful in 1m10s
ci / test (3.12) (push) Successful in 1m18s
ci / test (3.9) (push) Successful in 2m31s
ci / test (3.12) (pull_request) Successful in 2m28s
ci / test (3.14) (pull_request) Successful in 2m55s
ci / test (3.9) (pull_request) Successful in 3m0s
26b3879c50
Implements docs/backlog/020c-gui-generate-scenario.md (020a/020b merged
in #32/#33):

- "Generate scenario" button in the bottom controls row (left of
  Generate): same pre-flight as _on_generate (can_generate gate ->
  scenario_from_model -> validate, identical status messages), then
  draw_channels so resolved_seed and the drawn channels are recorded,
  then a save dialog (initialfile from the output-path stem) and
  serialization — no IQ generation, no worker thread
- controllers.scenario_sidecar_document: shared document builder
  (scenario to_json + drawn channel entries incl. fdma_channel +
  generated_by) matching generate_to_file's sidecar shape minus the
  IQ-run-only fields (feasibility verdicts are recomputed by the CLI;
  peak/samples belong to the IQ run)
- generation lock: disabled while a job runs (same pattern as 020b)
- docs: module docstring layout comment, README GUI section, backlog
  overview rows (020a/020b marked done; 020c done on merge), work orders
  archived to docs/done with outcome notes

Tests: tests/test_gui_generate_scenario.py — headless sidecar round trip
(GPS + GLONASS :chan + power offset, resolved_seed recorded), CLI parity
(gengnss scenario <gui file> -o a.i16 byte-identical to in-process
generate_to_file), no-dialog refusal on invalid model, lock behavior;
plus gui-marked handler/lock smoke. ruff clean; pytest 201 passed,
6 skipped (headless GUI).
ykp merged commit b95870d143 into main 2026-09-29 15:12:48 +02:00
ykp deleted branch feat/020c-gui-generate-scenario 2026-09-29 15:12:48 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
ykp/gengnss!35
No description provided.