# KOPR R149 — Multi-target formula document and atomic Save

**Base build:** `KOPR_CLEAN_BUILD_20260730_R148_MULTI_TARGET_SOURCE_ACTIONS.zip`  
**Date:** 2026-07-30  
**Scope:** final post-merger remediation batch for Comet Analyzer formula editing and persistence.

## 1. Implemented behaviour

### Single target

The historical simple editors are preserved:

```text
H0=7.24 mag, n=6.70 [-inf, 0]
H0=8.56 mag, n=4.59 [0, inf]
```

No `# TARGET` header is required for one selected comet.

### Multiple targets

Regular and Additional formula editors now display one complete document:

```text
# TARGET 4P | 4P/Faye
H0=7.24 mag, n=6.70 [-inf, 0]
H0=8.56 mag, n=4.59 [0, inf]

# TARGET 10P | 10P/Tempel
H0=5.50 mag, n=4.00 [-inf, inf]
```

The canonical designation after `# TARGET` is authoritative. The full display name after `|` is informational.

The parser rejects before any state or file change:

- text before the first target header;
- duplicate target blocks;
- unknown target blocks;
- missing selected targets;
- malformed formula rows;
- target blocks without any regular formula during Save.

### Target combobox

In multi-target mode, changing the selected target no longer replaces either editor. It moves the cursor to the matching target block in both Regular and Additional documents.

### Additional FormulaSeries preservation

Generated fit results remain typed `FormulaSeries` objects while their target block is unchanged. Manual editing converts only the changed target block to the established numerical/manual formula representation. Other targets retain their typed metadata, fit-group identity and series identity.

## 2. Atomic Save

Save now performs the following transaction:

1. Parse and validate the complete Regular document.
2. Prepare numerical formula maps for every selected target.
3. Prepare updated formula columns for every selected script row.
4. Read the existing `MagParams.dat`.
5. Preserve all unselected and malformed/comment records verbatim.
6. Replace selected records by exact canonical designation, avoiding prefix collisions such as `4P` versus `14P`.
7. Write one same-directory temporary file, flush and `fsync` it.
8. Commit once with `os.replace()`.
9. Only after a successful replacement, update in-memory formula maps and script rows.
10. Advance only the formula revision and redraw through the established formula path; observation loading is not restarted.

If parsing or the atomic replace fails, the existing file and all in-memory formula state remain unchanged.

## 3. Additional fixes included

- Formula parsing now handles explicit `-inf` correctly.
- Historical lower-bound spelling `[inf, inf]` remains compatible and is normalized internally to `[-inf, inf]` semantics.
- Leading whitespace before `H0=` no longer prevents a valid formula from being parsed.
- User-facing labels are pluralized to `Regular formulas` and `Additional formulas`.

## 4. New production and QA files

```text
light_curve_formula_document.py
r149_formula_document_release_gate.py
```

QA addition:

```text
tests/test_r149_multi_target_formula_document.py
```

The aggregate performance validator now includes the R149 module, release gate and QA test.

## 5. Regression results

Split cumulative regression execution:

```text
R100–R109: 115 passed
R110–R117:  78 passed, 1 skipped
R118–R129:  77 passed, 1 skipped
R130–R149: 135 passed
------------------------------------
Total:     405 passed, 2 skipped
```

The skipped tests require a PyQt5 runtime unavailable in the headless validation environment.

Release and distribution gates passed for both CLEAN and QA trees:

- R149 formula-document release gate;
- R148 source-action release gate;
- R147 typed-channel release gate;
- R146 sidebar/legend release gate;
- R145 hotfix release gate;
- cumulative WLightCurves merger gate;
- analysis release gate;
- modal ephemeris release gate;
- WPlanner performance release gate;
- Markdown hygiene;
- aggregate distribution validator;
- SHA256 manifest validation.

Final manifest sizes:

```text
CLEAN: 124 files
QA:    391 files
```

## 6. Scientific and architectural non-changes

R149 does not change:

- observation loading or channel classification;
- ephemeris mathematics or execution policy;
- canonical physical geometry;
- H0/n or phase-correction equations;
- independent, shared-n, perihelion or adaptive-break fitting mathematics;
- Multi-colour index arithmetic;
- WPlanner, WVisual, WCCD or WStack scientific behaviour.

## 7. Completion

R149 completes the planned R145–R149 post-merger remediation. The public Comet Analyzer now supports coherent editing, display and transactional persistence of Regular and Additional formulas for one or multiple selected comets.
