Comet Analyzer formula transactions and interactive gate
R179 completes the R177–R179 formula transaction work: one canonical parser, an explicit draft/commit model for manual editing, a separate atomic persistence operation and a real-PyQt5 qualification gate.
Qualification: RC / PASS_HEADLESS. R179 deterministic checks passed 13/13; the strict offscreen and native PyQt5 executions remain pending.
Formula state model
The production Analyzer separates editor drafts from committed formula state:
manual Regular/Additional editing
→ draft text only
→ explicit Refresh validates and atomically commits both documents
Analyse
→ typed fit result
→ immediate atomic commit
→ one implicit Refresh/renderKeystrokes never mutate the committed model, formula revision, rendered graph or persistent files. Intermediate text such as i, in, -, 1e or an unfinished interval is therefore safe while the user is typing.
Manual edit and Refresh transaction
- Editor signals store only the current Regular and Additional draft text.
- Refresh invokes the canonical typed document parser for both documents.
- Validation completes before any committed state changes.
- A valid pair is committed as one formula transaction, advances the formula revision exactly once and starts one plot update.
- An invalid pair leaves the previous committed formulas, formula revision and graph unchanged.
Formula validation errors use formula-specific titles and messages rather than the generic Plot rendering error.
Save transaction
Save retains the R149 same-directory temporary-file, flush, fsync and single os.replace() persistence boundary for config-files/MagParams.dat.
- An invalid Save leaves the existing file byte-identical.
- A valid Save writes the valid draft atomically.
- Save does not apply that draft to the committed graph and does not advance the runtime formula revision.
- The user applies manual draft changes through a separate valid Refresh.
This separation prevents file persistence from becoming an implicit GUI/model commit.
Analyse transaction
Analyse is intentionally not draft-only. Its typed fit result is committed immediately and one plot update is started as an implicit Refresh/render. It must not require a literal legacy button_click_update() dispatcher call.
The typed result remains inside the canonical R176+ Analyzer runtime and retains the existing transactional graph-preservation guarantees on failure.
Canonical parser and compatibility isolation
wlightcurves.py::_analysis_parse_formula_text()is removed.- The compatibility method
ParseFormulas()delegates directly to the canonical typed document/state parser and remains side-effect free. - Production
wlightcurves.pycontains no call tokoprobs.magparams(). light_curve_runtime.prepare_multi_target_curve_request()is compatibility-only and is not used by the typed Analyzer runtime.- Its legacy row conversion no longer imports or calls
koprobs.magparams(). - The converter retained in
koprobs.pyis compatibility-only for historical widgets or external callers.
Error and iterator-context contract
Expected or exceptional iterator exhaustion must retain the operation and target context. No production Analyzer path may print an unqualified bare StopIteration(). Invalid Refresh and invalid Save are handled as formula-transaction failures, not rendering failures.
Interactive qualification gate
R179 adds r179_formula_qt_smoke.py, r179_formula_interactive_release_gate.py and tests/test_r179_formula_interactive_qualification.py.
The real runner covers character-by-character i → in → inf input, no mutation during typing, one Refresh commit, invalid Refresh preservation, byte-identical invalid Save, corrected Save/reload and Analyse immediate commit.
QT_QPA_PLATFORM=offscreen python3 r179_formula_interactive_release_gate.py --require-qt
python3 r179_formula_interactive_release_gate.py --require-qt --nativeThe strict command must fail when PyQt5 is unavailable; a headless deterministic pass alone is not a full GUI qualification.
Source-reported qualification evidence
- R177: 9/9 PASS.
- R178: 9/9 PASS.
- R179 headless: 13/13 PASS.
- R179 real Qt: SKIP because PyQt5 was unavailable.
- R177–R179 targeted: 24 passed, 1 skipped.
- R149–R179 current regression: 236 passed, 3 skipped.
- CLEAN syntax: 107 files / 0 errors; QA syntax: 425 files / 0 errors.
- CLEAN manifest: 116 entries; QA manifest: 482 entries; aggregate validator and ZIP integrity: PASS.
The three skipped tests are the real PyQt5 gates from R154, R161 and R179.
Historical source-assertion boundary
Eight R141–R148 source-assertion tests require implementation details removed by the typed runtime, including obs_list, the old formula dispatcher and a literal self.button_click_update() call after Analyse. They contradict the R176–R179 architecture and are not valid R179 release evidence. Current behavioral gates are authoritative.
Formula document and persistence foundation · WLightCurves architecture · Supplied R179 report