KOPR DEVELOPER REFERENCE Baseline: R81 provenance and viewport hotfix — 27 July 2026 RUNTIME - Entry point: kopr.py - Host class: MainWindow - Tabs: Visual, WStack, WCCD, Planner, Analyzer, Comparison - Widgets are lazy-created once and stored in MainWindow._widget_cache. - Launch from the directory containing kopr.py because the source uses relative paths. PRIMARY MODULE OWNERSHIP - kopr.py: host shell, menus, active settings, tabs, hand-off, shutdown - wstack.py: WStack GUI, dialogs, Qt workers and host adapter - wstack_functions.py: master calibration, QC, astrometry, WCS validation, reprojection and stacking - wstack_common.py: FITS/RAW I/O, metadata, compatibility, saturation metadata and session state - wccd.py: manual CCD workflow and observation-local automatic helpers - autophot.py: shared numerical primitives retained by WCCD comet-finder and Auto Star Measure backends - acfcore.py: immutable local ACF context, PA-adaptive ring analysis and provenance - photom.py: aperture weights, ordinary photometry and compatible PhotometryACF API - cometcentroid.py: single canonical bounded 2D Gaussian CometCentroid definition - koprfunc.py: shared calculations, CometCentroid re-export, background, curve of growth, Af-rho and analysis functions - koprhand.py: settings/data files, catalogue/network services, ephemerides and persistent observation helpers HOST SETTINGS STRUCTURE settings[0] observer settings[1] defaults settings[2] active location settings[3] active telescope settings[4] active eyepiece settings[5] active camera WSTACK HOST SURFACES - ScrollWStack(parent, settings_provider, locations_provider, measure_stacked_callback, automatic_measure_stacked_callback) - refresh_host_settings() - shutdown_workers(timeout_ms) MEASUREMENT HAND-OFF - Manual: stack-group mapping -> MainWindow._measureStackGroup() -> WCCD.start_stacked_group_measurement(group) -> WCCD.start_automatic_stacked_measurement(job) STACKING INVARIANTS - Mean/sum: minimum 3 accepted frames - Sigma-clipped mean: minimum 7 accepted frames - Sigma clipping: exactly one symmetric median/MAD pass, default 5 sigma - Rejected samples are never restored - NCONTRIB = pre-clipping geometric coverage - NVALID = post-combination accepted count - Source saturation maps: NSATCON and NSATVAL - R73 saturation/camera integration: saturationpolicy.py shared authority; complete NSATVAL map or automatic/manual base; integer image-domain multiplier with effective_limit >= finite maximum; no observed-maximum copying; SATCOMP=NONE/nonexistent peak provider non-fatal when scalar resolution succeeds; exact and unique active-area camera acceptance before dialog RELATIVE WCS QC - minimum matches: 20 - minimum match fraction: 0.20 - maximum median residual: 0.70 px - maximum 90th percentile residual: 1.50 px - nearest-neighbour radius: 5 px PHOTOMETRY INVARIANTS - Manual WCCD and retained shared ACF primitives use pa-adaptive-upper-v1. - Only positive PA-local outliers are clipped; the negative distribution is not clipped. - Review preview/Apply changes only ACF analysis from the frozen context. - Automatic and manual results use the cumulative PA-adaptive ACF value; ordinary photometry does not overwrite it. - Detailed diagnostics use kopr-acf-provenance-v1 and compatible headers/logs receive a concise KACF line. - Instrumental convention: 40 - 2.5 log10(net_flux/EXPTIME); local sky is additive subtraction only. - Comet/Stars EXPTIME is validated within 0.001 s at observation preflight and then frozen; TOTEXP is reporting metadata only. - No PHOTSCAL, KPRSCAL or user-entered scale is part of production photometry. - Automatic background central estimator is the finite-pixel median. - Final automatic coma background uses local WCCD-shaped square-annulus geometry. - Candidate selection requires visual confirmation on the first pass. - Curve-of-growth model is physical single/broken power law; broken model requires >=4 apertures per side and Delta BIC > 6. TEST COMMANDS python -m py_compile kopr.py wstack.py wstack_common.py wstack_functions.py wccd.py autophot.py photom.py koprfunc.py python -m pytest -q tests python verify_autophot_build.py CURRENT SNAPSHOT TEST RESULT - Complete deterministic R81 QA: 1231 collected; 1225 passed; 6 skipped; 0 failed REBASE RULE Prefer the production host architecture; adapt the narrow WStack boundary. Never overwrite newer unrelated host fixes merely to apply an older patch. Run automated and live GUI/FITS smoke tests and publish a merge report with checksums. SCIENTIFIC / COMPACT STORAGE - settings.dat second positional row index 14: 0 Scientific, 1 Compact - access only through GetFitsOutputMode()/GetFitsOutputModeIndex(); preserve unknown trailing values - computation remains float; writer is selected at task start - Scientific: float32/NaN; Compact: scaled int16 with BLANK=-32768 - accept Compact only when QSTEP <= 0.25 * robust local sigma - unsafe output falls back per file to Scientific without clipping - WCS update preserves storage and extensions without requantization - readers normalize supported integer/float FITS to detached C-contiguous float32 STACK TIME / EXPOSURE - effective epoch = exposure-weighted input midpoint; DATE-OBS/DATE-MID/DATE-AVG and MJD equivalents - DATE-BEG/DATE-END bound accepted exposures; TELAPSE includes gaps; TIMEALGO=EXP-WMID - TOTEXP=XPOSURE=sum accepted exposures; EXP_NR=NCOMBINE compatibility alias - MEAN/SIGCLIP EXPTIME=one input exposure; SUM EXPTIME=total VALIDATION python validate_scientific_compact.py --json validation.json --csv validation.csv --markdown validation.md python validate_scientific_compact.py --compare scientific.fits compact.fits --json pair-validation.json python validate_scientific_compact.py --source input.fits --output-dir validation-products --keep-files R61 cumulative validation: 75 focused cumulative PASS; 78 centroid/finder/handoff/ACF PASS; 26 updated historical astrometry/integration PASS; retained R50 policy 13 tests OK; complete QA 986 passed, 3 skipped in 105.81 s, no failures. Production/QA compilation, manifest validation, forbidden artifact scan and ZIP integrity PASS. R55 robust stellar FWHM/background construction remains active. R48 astrometry, R47 saturation, R45 robust local solving, R40 role routing, R29 GUI, R27 photometry and R22 performance contracts remain inherited; the five-observation archival FITS protocol and a live 169P field run remain outstanding. R22 performance release validation python3 validate_performance_release.py python3 validate_performance_release.py --json R27 photometry release validation python3 validate_photometry_release.py Fixed concurrency: master median 4 threads; LIGHT calibration, row reprojection and sigma clipping 2 threads; astrometry 2 isolated external processes. Worker and memory limits are not user settings. R29 GUI INTERACTION CONTRACT - Mean and sigma_clip_mean share a compatibility family; their switch only toggles sigma controls. Transitions involving sum rebuild groups. - Saturation level is between Binning and Nr. of frames in the WCCD left panel. - Perform comet measure requires positive aperture plus finite centre, selects the Comet image if needed and invokes the existing measurement path without a confirmation dialog. - _StackPathLineEdit click or Enter/Return queues the named Browse handler; Tab/Shift+Tab does so only when empty. - Browse Cancel preserves the path; modal re-entry and duplicate queued requests are suppressed; Stars Clear is unchanged. - Comparison Load/Save Cancel returns immediately; UTF-8 context-managed I/O and safe post-Add-Comet reload are required. R45 ROBUST OFFLINE ASTROMETRY - Three attempts maximum: source FITS; robust copy + original constraints + downsample 2; robust copy + broad fallback. - astro__clean_solver_image() writes only a temporary FLOAT32 copy and preserves multi-pixel stars. - Adaptive failure returns to the independent frame seed at attempt 2. - Default required-anchor policy commits SKIPPED_ANCHOR_FAILED for remaining group frames. - Independent-seed continuation is explicit and per group. - Discover 4100/4200 sibling families; 4100 is optional; automatic download stays 4206–4214. - Record input mode, downsampling and replaced-impulse count in structured result, terminal line and attempt log. R47 COBS AND FLOAT SATURATION CONTRACT - COBS identifiers are case-sensitive. - APASS direct Sloan g'/r'/i': AG, AR, AI. - APASS calculated R/I share AR/AI with direct Sloan-r/i. - Gaia identifiers: Bg, Vg, Rg, Ig, gg, rg, ig, zg. - Automatic saturation priority: complete map; explicit detector metadata; detector bit depth; integer physical storage ceiling; FLOAT 0-1 -> 1.0; other FLOAT -> editable non-authoritative 65535. - Never copy the observed image maximum into the saturation field. R48 ASTROMETRY INPUT CONTRACT - Online nova.astrometry.net uploads are blind: no centre, radius, scale, parity or downsampling constraints. - Poll calibration only after status=success; queued/solving states emit heartbeats. - Successful online centre/scale is trusted for the subsequent local solve. - Offline position: FITS WCS; FITS pointing; per-frame internal ephemeris only when FITS has no usable position. - Offline scale: FITS WCS/pixel-scale metadata; active optics with FITS binning; standalone fallback only when needed. - Both RA/DEC fields or both scale fields must be edited to create an override; accepting displayed automatic values does not freeze them. - Clearing both scale fields restores automatic scale. - Position source, Scale source and redundant Astrometry parameters controls must remain absent. R59/R60 WCCD FINDER AND CENTROID CONTRACT - interactive WCCD candidate search radius 120 arcsec; unattended full automatic photometry stays 30 arcsec; - Primary/Extended classification and displayed C1..Cn identifiers are retained; - circle/row selection and M1 use one canonical bounded 2D Gaussian CometCentroid; - the only production definition is cometcentroid.py; koprfunc.py re-exports it and autophot.py calls it; - pan/zoom click suppression and valid zero-candidate review remain; - confirmation commits only the centre, which is authoritative for marker, Slice, aperture and ACF. R55 AUTOMATIC STAR MEASURE CONSTRUCTION - one pipeline for ordinary/crowded fields; R50 acceptance limits unchanged; - finite/in-image projection guard and mask-aware centroid without NaN zero-fill; - centroid search separated from compact adaptive FWHM/elongation profile; - local log-signal 2D Gaussian, fallback masked compact moments; - robust FWHM from isolated quality stars or lower 30% guarded distribution; - plateau/fallback and isolation use robust FWHM; fallback 3.5x, cap 4.0x; - final blend gate max(original, aperture + 0.75x robust FWHM); - any invalid non-zero-weight aperture sample => invalid_aperture; - partial-annulus spatial checks and balanced_boxes fallback only for geometry/coverage; - exact centroid/background subreasons and expanded diagnostics; - do not reuse this stellar profile for Comet Finder/trail-contamination scoring. R50 AUTOMATIC STAR MEASURE ACCEPTANCE CONTRACT - elongation tiers: <=2.2 standard, 2.2–2.7 moderate_elongation, >2.7 reject; - <3 final stars FAIL, 3–7 WARNING, >=8 normal; >40% clipping WARNING only; - scatter <=0.08 OK, 0.08–0.15 WARNING, >0.15 FAIL with zero point/scatter retained; R56/R57 PERSISTENCE CONTRACT - settings.dat restores active Location/Telescope/Eyepiece/Camera without forcing index zero. - settings.dat writes use flush + atomic replacement. - WStack uses separate wstack/comet and wstack/stars QSettings namespaces. - Method/sigma and comet output mode save only after successful validation. R58 COMMENT CONTRACT - Results/ICQ/COBS comments must not receive automatic Saturation text. - Keep saturation validation and provenance in diagnostics. R61 RELEASE GATE - complete QA: 986 passed, 3 skipped, no failures. - do not restore obsolete pre-R48 selectors or constrained-online payloads. - successive-frame astrometry-seed optimisation remains outside the release. R73 SATURATION/CAMERA INTEGRATION - CURRENT R73 QA: 1125 passed, 3 skipped, 0 failed; focused gate 75 passed. - 240P audited result: base 65535, maximum 1036396.5625, multiplier 16, effective 1048560 ADU. - 1370x1002 at 3x3 reconstructs 4110x3006 VERIFIED_EXACT; unique 4096x3000 active area is VERIFIED_COMPATIBLE. R74 AUTOMATIC DSLR RAW MATERIALIZATION BOUNDARY - CURRENT R74 focused QA: 58 passed, 0 failed; last complete baseline R73: 1125 passed, 3 skipped, 0 failed. - rawmaterialization.py owns materialize_raw_records(); WStack must not decode RAW directly. - WStack automatically dispatches discovery.extraction_candidates to the worker when rawpy/LibRaw is available; no confirmation or bypass dialog remains. - RawMaterializationWorker and RawExtractionProgressDialog keep decoding outside the GUI thread. - Discovery and automatic RAW resolution precede session mutation; a fatal resolution failure preserves _base_dir, preview and prior state. - post-resolution rediscovery verifies provenance/fingerprints, selects a new/refreshed or first verified green FITS and builds FITS-only _session_files. - wstack_common.migrate_raw_state_paths_to_fits(root, raw_to_fits) precedes reconcile_session(). - never overwrite unrelated/conflicting FITS or commit an incomplete final product. - R69 state-migration and FITS-only invariants remain inherited; R74 removes the extraction decision/bypass branch and keeps the same worker/progress service. R79 CUMULATIVE CONTRACT - R75: guarded master-flat correction; one-pass Stack Parameters preflight. - R76: explicit camera identity; validated observation binning; shared physical-scale priority; DE440s down-leg light-time; no universal external residual threshold. - R77/R78: one lossless canonical AutoStars/Manual Stars collection; extinction before global pairwise selection; strict abs(q_i-q_j) < 0.150 mag; user_enabled separate from pairwise_accepted; one accepted-ID set/final solution for Reference stars, Process obs. and Af-rho; no parallel post-success scatter gate or ICQ pairwise audit text. - R79 adds documentation/QA only relative to R78 production Python. R80/R81 HOTFIX CONTRACT - ReferenceStarTableModel Use derives from user_enabled AND quality_eligible AND pairwise_accepted is not False. - Pairwise status column remains removed; Reason is the visible exclusion diagnostic. Canonical internal states remain separate. - Direct TG FITS carries RAWREP=T; CALIB/WCS derivatives carry RAWREP=F; stacks strip direct single-source RAW identity cards. - Discovery recognizes derivative markers/legacy names before treating RAWFILE/RAWEXT as direct identity. - Repeated measurement on the already active role must not call image activation/redraw; wrong-role selection still switches once. - R81 complete QA: 1231 collected, 1225 passed, 6 skipped, 0 failed.