Comet Analyzer display encoding, point size and artist invariance
R161 qualifies the display-style domain, R164 fixes artist composition, and R169 adds a persistent global observation Point size without changing scientific or range identity.
Qualification: R169 point-size gate PASS 10/10 under headless/static GUI qualification. The cumulative package remains PASS_HEADLESS / RC because the separate R154/R161 real-PyQt5 gates are still pending.
Default encoding: Comet colour / channel marker
In the default encoding, target identity is carried by colour and observation-channel identity by marker shape. Target reordering must not assign a different identity to an existing comet, and channel filtering must not alter the stable identity of channels that remain.
Reverse encoding: Channel colour / comet marker
In reverse mode, observation channels use colour and comets use marker shape. Model curves remain neutral. Sparse target markers are applied only when multiple comets are selected; with one comet they are disabled because they add no identity information and could be mistaken for observations.
The sparse marker placement is a rendering concern represented by the Matplotlib markevery contract. It must not change formula sampling, geometry coverage or fitted values.
R164 observation-coordinate invariance
The committed observation visibility mask was already identical in both display modes. R164 adds a release-blocking regression invariant that renders the same pre- and post-perihelion arrays in both modes and compares the complete X/Y sequences. The sequences must be identical; only Matplotlib colour, marker and marker-face properties may differ.
Visibility selection is applied before any colour or marker resolution. Point style therefore cannot alter observation loading, filtering, magnitude reduction, fit membership, range ownership, ephemeris results or physical geometry.
Artist z-order
| Artist | z-order | Contract |
|---|---|---|
| Formula lines and optional formula markers | 2.0 | Background analytical presentation |
| Observation points | 4.0 | Always visible above formula artists |
This prevents black formula markers from covering coloured observations at nearby or identical coordinates.
Formula-marker policy in reverse mode
- Single target: formula markers are disabled and Formulae legend entries are line-only.
- Multiple targets: sparse target markers remain on neutral curves because they disambiguate comet identity.
The policy changes only artist composition. Formula sampling, markevery spacing for the multi-target case and scientific values remain unchanged.
Perihelion-side fill
Both encoding modes use marker face to carry perihelion side: pre-perihelion observations are hollow and post-perihelion observations are filled. This dimension is independent of comet and channel identity.
Rendered identity legends
The renderer owns four semantic legend blocks:
- Comets — target identity;
- Data channels — rendered channel identity;
- Perihelion side — hollow versus filled markers;
- Formulae — model-curve identity.
Legend content is derived from artists that were actually rendered. A filtered-out or absent target/channel must not remain as a stale legend entry.
Style editing transaction
The production feature provides compact target-style editing, dynamic channel Marker/Colour editing and the global R169 Point size controller. Target/channel edits become authoritative only through the established confirmation transaction; abandoning or rejecting an edit preserves the previous committed style state. Point size commits immediately as a display preference and causes a render-only update.
R169 global observation-point size
WLightCurves exposes one compact QDoubleSpinBox below Point style. The state value is global to the Comet Analyzer display layer, ranges from 1.0 through 12.0 in 0.5-point steps and defaults to 3.0.
The renderer applies the resolved value to both pre- and post-perihelion observation artists. It deliberately does not resize formula markers or legend keys, so the control cannot change formula identity encoding or semantic legend layout.
The state transition is strictly view-only:
persist display preference
increment view revision
redraw prepared plotIt must not reload observations, request geometry, call an ephemeris, rerun fitting or formula materialization, or invalidate the R163 range identity.
Atomic JSON persistence
Confirmed target/channel overrides and Point size are persisted in config-files/light_curve_display_styles.json. R169 adds the backward-compatible optional member:
{
"point_size": 6.5
}Files from R160–R168 without the member load at 3.0. An invalid, non-finite or out-of-range value is rejected independently and must not discard valid target/channel overrides. Reset all display defaults restores Point size to 3.0.
The committed file state and in-memory state must represent the same confirmed display transaction; partial writes are not an accepted state.
Identity and palette stability
- Known filters use their production default palette.
- An unknown observation channel receives a deterministic colour rather than a random session colour.
- Reordering selected targets or channels preserves existing target/channel identity.
- Only rendered identities appear in legends.
- Persistence restoration in a fresh instance must reproduce the confirmed overrides exactly.
Marker capacity and deterministic fallback
Reverse mode supports unique comet markers for at most 15 targets. At 16 targets, the resolver must fall back automatically and deterministically to the default Comet colour / channel marker encoding. It must not reuse ambiguous comet markers or fail unpredictably.
View-only and scientific boundary
Encoding selection, target/channel style actions and Point size are view-only. They may rebuild Matplotlib artists and legends, but they must not reload observations, invalidate canonical physical geometry, start an analytical worker, alter formulas, repeat fitting, change photometric values or call an ephemeris.
Point size changes only the observation artists. Formula-line markers and legend keys are invariant. Display-style changes, including Point size, preserve the current R163 AUTO/USER plot-range state and Matplotlib zoom because they are excluded from AnalyzerRangeIdentity.
R161 deterministic release gate
The headless gate executes production style resolvers and real Matplotlib artists. The supplied report records all 12 checks as PASS:
default_artist_encoding
reverse_artist_encoding
perihelion_fill
reverse_formula_artist
rendered_identity_legends
filter_palette_and_unknown_channel
reorder_preserves_identity
marker_capacity_and_fallback
persistence_fresh_instance
transactional_gui_contract
style_actions_are_view_only
qt_gate_artifacts_presentSource-reported tests: 31 passed, 1 skipped for R158–R161 and 234 passed, 2 skipped for the cumulative R130–R161 Analyzer suite. The skips are the real PyQt5 tests from R154 and R161.
R164 hotfix release evidence
The supplied report records 6 targeted tests, 40 passed in the focused R159/R162/R163/R164 set, 266 passed, 2 skipped cumulatively, and an R164 6/6 PASS release gate.
R169 point-size release evidence
The supplied report records 7 focused tests, 10/10 release-gate PASS and 152 passed, 1 skipped for the R151–R169 Analyzer regression. Renderer and persistence behavior were executed directly; the Qt widget structure was statically validated.
The single skip is the existing real PyQt5 offscreen smoke test. R169 therefore passes its headless/static qualification but does not close the historical R154/R161 GUI qualification gap.
Remaining real-PyQt5 qualification
The build host had Xvfb but no Python PyQt5 binding. The strict gate therefore correctly returned qt_runtime_unavailable, and the package remains an RC.
QT_QPA_PLATFORM=offscreen python3 r161_comet_analyzer_display_encoding_release_gate.py --require-qt
python3 r161_comet_analyzer_qt_smoke.py --nativeThe first command must report status: PASS. The native run must then complete the R158–R161 visual checklist. Missing PyQt5 coverage must never be converted into a headless release PASS.
User display-encoding guide · R154 state machine · Supplied R161 report