WStack integration contract
The narrow, reproducible interface between the KOPR host, WStack and WCCD measurement workflows.
Source-verified The contract was consolidated from the maintained merge plan and the host callbacks present in the audited source baseline.
Owned files and dependency boundary
WStack is implemented by three root-level files:
wstack.py— tab GUI, dialogs, workers and host adapter;wstack_functions.py— calibration, QC, astrometry, reprojection and stacking algorithms;wstack_common.py— frame loading, normalized metadata, FITS/WCS helpers and session state.
It uses the production host's koprfig.ImageDialog and host settings adapter. A WStack delivery must not overwrite the production koprfig.py with a private copy.
Host construction and lifecycle API
The current host constructs WStack as:
wstack.ScrollWStack(
parent,
settings_provider=host._settingsSnapshot,
locations_provider=host._locationChoices,
measure_stacked_callback=host._measureStackGroup,
)
| Surface | Direction | Contract |
|---|---|---|
refresh_host_settings() | Host → existing WStack widget | Refresh displayed active location/telescope/camera without creating a new tab. |
shutdown_workers(timeout_ms) | Host → WStack | Cancel and join owned workers; return false if safe shutdown is incomplete. |
settings_provider() | WStack → host callback | Return the current historical KOPR settings structure. |
locations_provider() | WStack → host callback | Return all configured observing locations. |
| manual measurement callback | WStack → host | Pass one validated stack-group mapping to WCCD. |
ScrollWStack(parent) remains usable with standalone fallbacks, but the integrated host should supply providers/callbacks rather than allowing WStack to infer main-window internals.
Host settings mapping
settings[2] = active location
settings[3] = active telescope
settings[4] = active eyepiece
settings[5] = active camera
Expected rows: location: name, longitude, latitude, altitude, GMT; telescope: name, type, aperture, focal length, optional fixed zoom/FOV; camera: name, camera code, chip name/code, X/Y resolution, X/Y pixel size, optional spectral peak.
R56 requires these four active rows to survive restart. Do not restore the old behaviour that forced menu index zero after Settings or startup. Persist by flushed atomic replacement of settings.dat. If a future KOPR version changes the schema, modify WStack's host-context adapter only; do not distribute new raw indices through astrometry, stacking or photometry functions.
R57 keeps WStack operation preferences separate from host configuration. Save validated method/sigma values in wstack/comet and wstack/stars; save comet output mode with the Comet namespace. Cancelled or invalid dialogs must not commit preferences.
Matched-stack measurement contracts
Measure route
The host callback requires a mapping with a valid comet stack path, an optional stars stack path, a positive frame count and pair metadata. The host creates/reuses WCCD, switches to its tab and calls start_stacked_group_measurement(group). The ordinary New CCD/DSLR observation dialog opens with transferred values as editable defaults. R29 preserves one named Browse handler per path, click/Enter activation, empty-field-only Tab activation, modal/re-entry guards, Cancel path preservation and the existing Stars Clear action.
Stack-method dialog
Mean and Sigma-clipped Mean must remain one compatibility-group family: changing between them only toggles the sigma control. Entering or leaving Sum must rebuild groups because the exposure compatibility contract changes.
ACF and Review integration boundary
The ACF/Centroid/GUI merge adds production acfcore.py plus coordinated changes in wccd.py, autophot.py and photom.py. A later WStack rebase must not overwrite these newer files with an older integration baseline.
Preserve pa-adaptive-upper-v1, immutable ACFMeasurementContext, context/run invalidation, Review button placement, compatible PhotometryACF() return values and kopr-acf-provenance-v1. Resolve conflicts semantically rather than restoring the former symmetric ACF implementation.
Operational priorities to preserve
Topocentric position
- manual MPC observatory code when explicitly supplied;
- active KOPR longitude, latitude and altitude;
- geocentric fallback only when no observing site is available.
FITS acquisition times are UTC. The configured GMT field must not be added to DATE-OBS.
R48 astrometry input contract
- Offline position: complete FITS WCS; FITS pointing; internal per-frame comet ephemeris only when FITS has no usable position.
- Offline scale: FITS WCS/pixel-scale metadata; active KOPR optics with FITS binning; standalone fallback only when integrated geometry is unavailable.
- Manual override: both fields in the RA/DEC or scale pair must be edited; accepting displayed automatic values does not freeze them. Clearing both scale fields restores automatic scale.
- Online: blind FITS upload with an empty constraint dictionary; no offline-parameter dialog; calibration requested only after server success.
scale_x = 206.265 × pixel_x_um × XBINNING / focal_length_mm
scale_y = 206.265 × pixel_y_um × YBINNING / focal_length_mm
scale = sqrt(scale_x × scale_y)
The local solver interval remains ±15% around this estimate.
Solver backend and index ordering
- native
solve-fieldonPATH; - on native Windows, the default or explicitly selected WSL distribution;
- fail once with an actionable error when no backend is usable;
- check/download indexes only after solver preflight succeeds.
Preserve KOPR_WSL_DISTRIBUTION, wslpath-based path translation, solve-field/WSL provenance and process-group cancellation. Do not replace argument-token passing with shell-interpolated paths.
R45 solver retry and group guard
- preserve the three-attempt ceiling and attempt ordering;
- create robust copies only in isolated work directories and never mutate calibrated inputs;
- return from a failed adaptive seed to the frame's independent seed on attempt 2;
- keep Stop and skip remaining frames as the default required-anchor policy;
- retain the explicit independent-seed override for heterogeneous groups;
- discover 4100 and 4200 siblings while keeping 4100 optional and automatic download at 4206–4214.
R47 WCCD source and saturation fallback contract
- Preserve exact case-sensitive COBS identifiers. APASS Sloan g′/r′/i′ are
AG/AR/AI; calculated R/I shareAR/AIwith the corresponding direct Sloan sources; Gaia identifiers retain their defined mixed case. - Do not use the observed image maximum as a saturation threshold.
- After complete
NSATVALand explicit detector metadata, detector bit-depth metadata must outrank the wider integer storage ceiling. - Floating 0–1 data resolve to
1.0; other floating data without metadata resolve to editable non-authoritative65535. - Keep Comet and Stars threshold state independent and retain the R40 manual-override semantics.
Repeatable production rebase
- Archive the production baseline. Record its checksum and create a clean working copy.
- Compare host surfaces. Inspect current
kopr.py,koprhand.py,koprfig.pyand WCCD construction before applying old edits. - Start from the latest stabilized WStack trio. Do not reintroduce an older test ZIP after later QC/photometry fixes.
- Apply host changes by semantic anchor. Import WStack, add/reposition its persistent tab constants, extend the lazy factory, supply callbacks/providers, refresh existing context and include worker shutdown.
- Verify the settings adapter. Confirm row shape and units; adapt only the boundary when needed.
- Keep production shared modules. Do not overwrite
settings.py,koprfig.py,datavar.pyor unrelated tabs merely to make an old patch apply. - Run syntax and automated tests. Use
python -m pytest -q testsandverify_autophot_build.py. - Run the live regression checklist. Exercise tabs, settings, workers, calibration, astrometry, stacking and the Measure hand-off into WCCD.
- Write a merge report. Document every intentional divergence, test result and final archive checksum.
Integration regression checklist
Host
- all six original positions remain stable and open lazily;
- current selection and status bar remain correct;
- Configuration menus change active settings normally;
- active Location/Telescope/Eyepiece/Camera survive restart and are not forced to index zero;
settings.datwrites are flushed and atomically replaced;- no duplicate menu or toolbar item is introduced;
- application shutdown stops WStack workers safely.
WStack GUI
- opens as the integrated tab, not a second top-level main window;
- Raw/Calib/Astro/Stack pages work;
- preview uses production
koprfig.ImageDialog; - WStack settings retain API key/fallbacks;
- Comet and Stars method/sigma preferences remain independent, comet output mode persists, and Cancel/invalid input does not save;
- active host context refreshes after configuration change;
- all user-facing text remains English.
Astrometry backend
- native solver remains preferred;
- native Windows falls back to the selected WSL distribution;
- solver preflight precedes index checking/downloading;
- Windows paths, including spaces, translate through
wslpath; - generated WSL config uses WSL-visible paths and LF endings;
- provenance records
solve-field/WSL; - Cancel terminates the Linux solver process group without shutting down the entire WSL distribution;
- missing launcher/package failures do not retry every frame.
- each frame performs no more than the documented source/robust/robust-broad three-stage sequence;
- the robust temporary input removes isolated impulses without changing the calibrated source or multi-pixel stellar profiles;
- required-anchor failure produces one FAILED result and deterministic SKIPPED_ANCHOR_FAILED group results under the default policy;
- the independent-seed continuation policy is explicit and per group;
- 4100 and 4200 sibling families are discovered, missing 4100 remains non-fatal and automatic download remains 4206–4214;
Pipeline and hand-off
- DSLR discovery occurs before session mutation and automatically sends pending/stale candidates to materialization;
- no confirmation or RAW-bypass branch remains;
- RawMaterializationWorker and progress dialog run outside the GUI thread with cooperative between-file cancellation;
- post-resolution rediscovery produces a FITS-only
_session_filesindex and migrates historical RAW state paths to verified TG FITS; - conflicting targets are preserved and incomplete final FITS is never committed;
- master dark/flat, LIGHT calibration and astrometry;
- AXY diagnostics and relative-WCS OFF persistence;
- star stack, manual comet stack and automatic topocentric comet stack creation;
- instant Mean ↔ Sigma-clipped Mean switching without a group rebuild, while transitions involving Sum do rebuild;
- mean, sum and single-pass sigma-clipped mean;
- deterministic names and overwrite behavior;
NREQUEST,WCSREJ,NCOMBINE,NVALID, saturation maps and provenance;- Measure hand-off opens the editable WCCD observation dialog and preserves transactional helper start;
- Comet/Stars path fields share their named Browse handlers, suppress modal re-entry/duplicate requests and preserve paths on Cancel;
- the WCCD direct comet-measure button follows positive-aperture and finite-centre state and uses the existing measurement path.
Scientific/Compact and FITS contract
- old settings without index 14 default to Scientific;
- settings access uses central getters and preserves unknown trailing fields;
- new masters, calibrated LIGHTs and all stack methods use the selected writer;
- unsafe Compact products fall back per file without clipping;
- actual and requested storage/policy keywords are consistent;
- auxiliary HDUs remain lossless and compatible with both modes;
- WCS updates preserve pixel storage and extensions without requantization;
- weighted stack time and method-specific exposure contracts replace inherited reference-frame cards;
- manual WCCD accepts supported external integer/float FITS;
validate_scientific_compact.pyruns on synthetic, paired and source-writer cases.
Performance release contract
validate_performance_release.pypasses without importing PyQt, NumPy or Astropy;- numerical scheduling remains thread-based and does not use Python process pools;
- no thread-count or memory-limit control appears in the user interface;
- master median is bounded to four threads; LIGHT calibration, row reprojection and sigma clipping are bounded to two;
- the prepared-master cache and shared memory allowances remain bounded;
- astrometry runs no more than two external solver processes with isolated working directories;
- serial fallback remains available for small jobs, one-CPU systems, insufficient RAM and scheduler initialization failure;
- Windows/WSL commits remain deterministic and cancellation removes active processes and
.solve_*work directories.
WCCD Automatic Helpers integration boundary
A later WStack or WCCD rebase must preserve ephemeris_position.py, cometfinder.py, cometcentroid.py, starmeasure.py, named measurement-mode IDs, observation-local state machines, stale-worker guards, atomic star commits, Slice overlays and the persistent ACF Review ownership rule.
- Keep interactive candidate detection at 120 arcsec and unattended complete automatic photometry at 30 arcsec. Preserve Primary/Extended classification, post-filter
C1..Cndisplay IDs, zero-candidate review and pan/zoom click suppression. - Manual WCCD clicks, automatic candidates and
M1must all call the canonical bounded 2D GaussianCometCentroidfromcometcentroid.py. Do not create a second production centroid definition. - Confirmation commits only the accepted centre; it must not start photometry. The accepted centre remains authoritative for state, marker, Slice, aperture measurement and ACF.
- Preserve the R50 shape tiers, standard-first common-aperture ordering, stable-increment plateau rule, star-count warning/failure levels and scatter decision.
- Preserve the R55 one-pipeline contract: lightweight projection guard; mask-aware stellar centroid without NaN zero-fill; separate compact-profile FWHM/elongation; robust isolated/lower-distribution FWHM; 3.5× robust-FWHM fallback capped at 4.0×; post-aperture blend gate; strict invalid-aperture policy; checked partial-annulus and
balanced_boxesbackground paths; precise rejection diagnostics. - Do not route the R55 stellar profile into Comet Finder or stellar-trail contamination scoring without a separate validation batch.
- Keep basic WCS matching, catalogue/colour routing, saturation provenance, S/N sequence and individual-zero-point clipping algorithm unchanged unless a separate scientific migration explicitly replaces them.
- Do not re-add automatic
Saturation:text to Results, ICQ or COBS comments. Keep saturation policy/provenance in diagnostics.
Do not decode physical DSLR RAW inside WStack orchestration or reintroduce physical RAW paths into the working index. Keep rawpy optional when a directory contains only usable existing FITS, but require it whenever pending or stale DSLR representations must be materialized automatically.
Do not make astroquery a hard dependency. Do not restore Review invalidation on Stars-image, catalogue or photometric-option changes. Do not introduce the postponed successive-frame astrometry-seed optimisation as part of this documentation/rebase contract. Resolve conflicts by separating numerical backend, GUI controller and commit layer.
R74 automatic DSLR materialization contract
- Use metadata-only discovery and
discovery.extraction_candidates; do not decode RAW inwstack.py. - Start
_run_raw_materialization_batch(discovery)immediately when pending/stale candidates exist and rawpy/LibRaw is available. - Retain
RawMaterializationWorker,RawExtractionProgressDialog, cooperative cancellation and atomic temporary-product validation. - After resolution, run discovery again and build the session only from
fits_only_root_inputs(discovery). - Prefer the first newly created/refreshed TG FITS; otherwise select the first verified
record.representation_path. - Missing rawpy/LibRaw must produce the critical extraction-unavailable path, never direct RAW loading or a bypass choice.
- Conflicting targets remain separate warnings and must not be overwritten.
- Resolve all RAW conditions before mutating
_base_diror replacing the open session.
R79 cumulative integration contract
- Preserve the R75 master-flat correction guard and the one-pass Stack Parameters preflight without changing calibration/stack pixels.
- Keep camera identity/native geometry separate from validated observation binning.
- Use one shared physical-scale priority: solved WCS/online calibration, explicit manual override, FITS metadata, then active optics with validated binning.
- Preserve internal DE440s down-leg light-time and treat Guide/Tycho/Horizons residuals as diagnostics without a universal arcsecond gate.
- Keep one lossless canonical reference-star collection for AutoStars and Manual Stars.
- Apply extinction to
q_ibefore a global strict pairwise solution; exactly 0.150 mag fails. - Keep
user_enabledseparate frompairwise_accepted. - Reference stars, Process obs. and Af-rho must consume one accepted-ID set and one final solution; do not add a parallel post-success scatter gate.
- Do not add internal pairwise audit text to the ICQ comment.
R80–R81 hotfix integration contract
- Do not map the Reference stars Use checkbox directly to
user_enabled. It must represent effective inclusion:user_enabled AND quality_eligible AND pairwise_accepted is not False. - Keep Reason as the single visible exclusion diagnostic and do not restore the redundant Pairwise status column. Preserve the lossless internal states separately.
- A direct materialized TG FITS carries
RAWREP=T; calibrated and astrometric derivatives carryRAWREP=F. - Final stacks must not retain the single-source cards
RAWREP,RAWFILE,RAWEXT,RAWMODE,RAWVERS,RAWSIZEorRAWMTIME. Preserve aggregate ancestry inHISTORY,REFIMAGE,NCOMBINEandPROVENANCE. - Discovery must treat derived-product markers and safe legacy names as evidence that historical RAW cards are ancestry, not direct-representation identity. Continue supporting legacy valid
_TG.fitswithoutRAWREP; continue blocking two genuine direct representations. - When a repeated measurement already has the required image role active, update the selector/mode without image activation or redraw. A role mismatch still requires the normal switch and redraw.
Conflict policy
- Prefer the newer production host architecture and adapt the narrow WStack adapter.
- Do not overwrite newer KOPR fixes merely to make an older patch apply.
- Preserve stabilized WStack processing APIs, relative-WCS behavior and the R40 role-specific saturation contract: complete
NSATVALauthority in automatic policy, per-image manual overrides, slot-local reset and exact-path threshold hand-off. - Preserve the validated R27 photometry flow and R22 automatic resource limits.
- When two branches disagree on numerical meaning, require reference-data evidence; do not choose the cleaner implementation by style alone.
- Document every intentional divergence from this contract in the merge report.
R73 saturation and camera integration contract
- Keep one shared saturation resolver in
saturationpolicy.py; do not reintroduce divergent manual, WCCD-helper or Automatic Star Measure calculations. - For scalar fallback, preserve automatic/manual base parity, integer image-domain scaling and
effective_limit >= finite_image_maximumwithout copying the observed maximum. - Do not turn
SATCOMP=NONEor a missing source-frame peak provider into blanket comparison-star rejection. Preserve flat-top and bleeding morphology vetoes. - Evaluate camera compatibility before opening the selection dialog. Exact native geometry and a unique supported active-area match must suppress the dialog.
- Preserve source-geometry × binning reconstruction and the
VERIFIED_EXACT/VERIFIED_COMPATIBLEdistinction.