Skip to content

October 16, 2026 (round 11)¤

Typed API, docs that run, coverage gate 93. feat: top-level imports are typed; deprecated names are visible to type checkers; transforms, features, ValueMapper, PipelineResult and the warnings/errors are top-level exports; loaders have redacting reprs. perf: scipy and scikit-learn are imported lazily; list_detectors does not import modules. fix: PostgreSQL loaders name the psycopg2 driver (SQLAlchemy 2.1), escape the password and take db_port / db_driver; discover_motifs applies an exclusion zone between motifs; startup by slope with repeated index labels; empty multi-signal startup results keep their columns; DatapointDB with an empty device. docs: every python block on the docs pages runs as a test; new module pages and guides (context, ML features, maintenance, energy); runnable class examples. See docs/migration.md. chore: coverage floor 82 -> 93.

October 15, 2026 (round 10)¤

Fast at 10 and 100 million rows; results unchanged. perf: detector construction copies, sorts and converts only what it must (no full-column text conversion, sort skipped on sorted input); 100M-row frames no longer run out of memory. perf: per-run and per-row Python loops in 19 detector modules replaced by numpy (utils.runs); O(n log w) rolling moments; setpoint KPIs share one window gather; STOMP matrix profile; vectorized DTW with LB_Keogh pruning; faster profile, to_event_log (same event ids), tolerance deviation and apply_ranges. change: ChangePointEvents defaults to method="auto" (PELT up to 20,000 samples, binary segmentation above). fix: setpoint KPIs no longer fail on duplicate index labels. chore: benchmarks/run.py and a scaling check in CI (pytest -m scale). See docs/migration.md.

October 15, 2026 (round 9)¤

KPIs match their textbook definitions. fix: durations and counter increments are split at shift, hour and day boundaries (downtime, availability trend, shift handover, runtime, micro stops, OEE, per-shift quality); OEE across midnight is correct; days without state data are NaN; performance above 100 % warns instead of being clipped. fix: PerformanceLoss counts parts; time_to_settle is the last band entry; overshoot/undershoot are percent (ratio twins added); period roll-ups recompute from summed bases; EnPI/SEC rolling baselines are ratios of sums; stockout prediction is refill-aware. fix: SPC individuals limits, rules and CUSUM use MR-bar/1.128 (sigma_method="std" keeps the old sigma); real moving-range and EWMA charts; Cp/Cpk within sigma, Pp/Ppk overall and per-window sigma. feat: utils.time_accounting; micro-stop performance_loss_pct; reference tests for KPIs in tests/reference. See docs/migration.md.

October 15, 2026 (round 8)¤

Legacy code and tooling removed. change: requires pandas>=2.2.2 and numpy>=2.0; a CI job tests these floors and results match pandas 3 (calendar-day windows on DST days, DST flooring, mixed UTC offsets, clustering). fix: deprecation warnings point at the caller and are no longer hidden; apply_ranges / segment_by_cut compare times in one unit; numeric columns named like times are no longer converted to datetimes; hour folders are UTC in every loader. change: logged data problems are DataQualityWarnings; text in numeric columns is reported; recipe duration_s, downtime_minutes input and old attribute names warn; loader time ranges are start / end (old start_timestamp / start_time keywords warn). See docs/migration.md. fix: CUSUM counts a repeated sample once. chore: setup.py, MANIFEST.in, requirements files, dead scripts and dead code removed; duplicated helpers merged; one source of tool versions; CI runs once per PR commit; per-job release permissions; examples linted; a ts-shape deprecation fails the test suite.

October 14, 2026 (round 7)¤

Robust and consistent behavior for every public function. fix: wrong results: CrossSignalAnalytics.lead_lag named the wrong leader; PatternRecognition dropped the timezone, ignored row order and mixed signals; event ids collided across machines so concat dropped events; ValueMapper/ContextEnricher dropped columns and codes; build_paths missed the last hour; boolean and string change filters missed edges; fill_gaps(max_gap) measured gaps wrongly; lead_times could be negative; reliability and stockout returned inf. fix: crashes on empty, single-row, all-NaN, text-time, nullable and pyarrow input across transforms, features, signals, profile, pipeline, event log and detectors; a missing column raises ColumnNotFoundError everywhere. change: canonical parameter names (value_column, time_column, uuid_column, window) outside the detectors; old names deprecated. No data gives NaN or None, unknown mapping codes are kept. See docs/migration.md. feat: max_gap on detect_flatline, threshold_with_hysteresis and on_off_intervals; contract tests for every public function; the invariant harness checks determinism, input mutation, row order, output sanity, all-NaN, single-row and duplicate timestamps.

October 14, 2026 (round 6)¤

Maturity of the existing functions: same numbers for any data source, fast on real data sizes, proven against references, traceable outputs. fix: results no longer depend on how the data was loaded. Nullable, pyarrow and text-number columns are converted once (utils.normalize): 52 methods gave different numbers (counter totals counted the first reading as production, downtime per shift was 0) and 172 crashed. Rows with the same timestamp are ordered by uuid. perf: shift reports, maintenance trend fits, routing, warmup and stockout methods are vectorized: 10-300x faster on 200k rows (nok_by_shift 59 s -> 1.3 s, remaining_useful_life 55 s -> 0.2 s). fix: DST fall-back nights no longer crash window flooring (floor_local); duplicate timestamps no longer give infinite rates; single-row and constant inputs, all-null/boolean string columns, and window <= 0 in oscillation detection are handled. fix: capability trending uses the spec in force in each window; energy methods with weekly/month-end windows report the real window (and energy_per_unit / carbon_intensity_per_unit no longer return empty or raise); downtime and shift handover read boolean run signals (was 100% downtime); flow_constraint_analytics applies its thresholds; from_shift_data matches string dates; detect_outlier_sensor needs three sensors to name an outlier. fix: group counter totals add up to the signal total (counter_by_group): every shift/day/operator/part/batch boundary lost one increment, and alternating operators or parts were double counted (609 parts reported on a 360-part counter). FlowConstraintEvents intervals end at the next change. change: KPIs carry their basis (run/planned/excluded seconds, parts, resets); every duration has a *_seconds column; seven summary methods return a DataFrame (as_frame=False deprecated). See docs/migration.md. test: reference tests for SPC rules 1-8, Cp/Cpk (Montgomery), GUM, Weibull (Lieblein-Zelen) and energy values; property tests; harness dtypes check; examples/ and docstring examples run in the test suite. types: strict mypy flags for the whole library, no exemptions. fix: cycles, period cutters and object detection verified against hand-built scenarios. Cycles: correct pairing for back-to-back and nested markers, deterministic cycle_uuid, one half-open boundary rule. Segments: the last period keeps its data, boundary samples are cut once, segment_by_cut is no longer one piece off. Objects: empty readings end a presence, change-encoded ids last to the data end, hand-over events link once, pm4py export round-trips. All three are 10-100x faster. feat: severity_level (info/warn/critical) next to every categorical severity, so detectors can be filtered together; detector labels stay. fix: lag_profile windows without speed data are NaN (was the lag at min_speed); CriticalParameterRankingEvents needs no long-format frame; TimeWindowedFeatureTable takes window (freq deprecated). docs: the site is cut from 139 to 106 pages (14k to 6k lines) and rewritten in plain language; every example runs.

October 14, 2026 (round 5)¤

Correct by default. Results change wherever data has counter resets, change-encoded signals, uneven sampling or several signals per frame; the old behavior stays one argument away. Full list: docs/migration.md ("Correct by default"). change: correct defaults: handle_resets=True, interval_end="next_change", time_weighted=True, group_by_uuid=True, slope_per="second", missing_as_zero=False, handle_refills=True, SPC include_severity=True, regex=False for substring filters, trim_to_range=True in loaders, best_and_worst_shifts returns a DataFrame, batch_transition_matrix returns a long from/to/count table (layout="wide" for the matrix). change: full precision: detectors no longer round results. fix: machine_running_pct is 0-100 (was a 0-1 ratio; see machine_running_ratio). fix: nothing is skipped silently: loaders take errors="warn"|"raise" and name unreadable objects; non-numeric values, malformed specs, failed fits and untestable windows warn with DataQualityWarning; a missing value column raises ColumnNotFoundError naming it. fix: flatline detection ignores single samples of regularly sampled signals. change: deprecated (removed in a future major release): OrderTraceabilityEvents, a single tolerance_uuid (upper/lower limits now work one-sided), station_map, adapt(legacy=), integer window in correlation, as_frame=False. Every deprecation message says "removed in the next major release". feat: OutlierDetectionEvents(signal_uuids=...); parquet extra; [all] installs every optional feature. build: setuptools-scm reads its config (builds were versioned 0.0.0); releases publish after the full CI suite, choose their version with a Release-Bump / Release-As commit trailer, and are tagged only after the upload succeeded; CI builds and checks the package; Python 3.14 is fully supported; Development Status: Beta. types: the mypy quarantine is empty; every module is type-checked. policy: every merge publishes the next patch version; renamed names keep working with a warning and are removed only in a major release.

October 14, 2026 (round 4)¤

fix: SPC rules follow Nelson (1984) / Western Electric: rule 8 = 8 in a row with none within 1 sigma (was within), rule 3 = 6 points, rule 4 = 14 points, rules 5/6 count outer zones per side, rule 2 uses the center line; rules no longer mutate the input; vectorized == per-rule results. fix: detectors do what their signatures and docs promise (28 items across production, quality, engineering, energy, development, loaders, features): ignored parameters now work or warn (slope_window, max_cycle_gap on every CycleTimeEvents method, idle_threshold per shift, interval_end on long-downtime gap counting and recipe phases, value_column in process alignment, ...); silently overridden ones warn (settle_pct vs tol, state_map vs station_map); tolerance deviations keep values and single samples; takt adherence uses strict > and ignores counter resets; golden batch phases compare like with like; hour-folder loaders include the end hour; NaN instead of None/0.0 for undefined ratios. Opt-in: time- weighted time_in_range, slope per second in drift detection, trim_to_range in loaders, regex=False for substring matching. Every result change is listed in docs/migration.md. docs: every public parameter is documented (guard test). change: consistent input checks for every detector (Base.init_subclass + utils.signal_checks): a signal uuid that is not in a non-empty frame emits DataQualityWarning naming the available uuids (one per call, not per internal sub-call); a missing time or uuid column raises ColumnNotFoundError (a ValueError) instead of a bare KeyError. change: parameters follow docs/naming.md: time_column (was column_name), window (freq/period/resample), window_size (integer row counts), n_sigma, lower_limit/upper_limit, warning/critical_threshold, include_initial, only_*, signal_uuids, run_state_uuid, value_column_ in energy. Old keywords work with a DeprecationWarning. Optional arguments are keyword-only (positional use warns). event_uuid defaults are ":" and unique (outlier_event -> quality:outlier, ...). tests/test_naming.py lints every detector signature. fix: rising-edge detection on an object column of Python bools (~True is -2, truthy) counted every True sample as a cycle end in CycleTimeEvents.cycle_time_by_part and LineThroughputEvents.takt_adherence / cycle_quality_check. change: one name per concept (docs/naming.md). Detector classes end in Events (DowntimeTracking -> DowntimeEvents, OEECalculator -> OEEEvents, 16 classes); event classes drop calculate_/compute_/process_ verbs (14 methods, e.g. calculate_oee -> oee, find_gaps -> detect_gaps) and use _statistics / _by_window suffixes. Old names are deprecated aliases that warn and are removed only in a future major release; the event log resolves them (taxonomy.resolve). See docs/migration.md. fix: every detector output now carries the canonical columns of its shape (intervals start/end/duration_seconds/uuid/source_uuid, summaries start/end/duration_seconds, points systime/uuid/source_uuid): 276 of 277 harness-callable methods conform, up from 78. Columns were only added, never removed or renamed. The taxonomy declares the shape each method really returns (69 corrected). Empty results keep the full column set; six methods that returned frames without columns now return the schema. The invariant harness checks shape and empty_schema for every method. fix: weekly / month-end windows ('W', 'ME', ...) reported the bin's last day as start; windows now span their real [start, end). fix: night shifts are one (date, shift) row: production_day=True is the default (False keeps calendar-date grouping, which split a night across two rows that each mixed two nights); downtime_by_shift, performance_by_shift and setup_durations gained the option. fix: CapabilityTrendingEvents.capability_forecast subtracted the window index twice, understating windows_to_threshold for later windows. add: ShiftReporting.best_and_worst_shifts(as_frame=True); the dict default emits a FutureWarning. add: ReliabilityEvents (events/maintenance/reliability.py) -- reliability KPIs from a failure-state signal (fault bit or status codes), built on signals.primitives.intervals so states hold until the next change and logging gaps (max_gap) are no data: failure_events (interval), mtbf_mttr (MTBF, ISO 22400 MTBF, MTTR, availability, failure rate; overall or per DST-correct calendar window), weibull_fit (censored MLE: beta, eta, MTTF, B10, failure pattern) and reliability_at (conditional reliability and hazard). test: ISO 22400 OEE reference example (A x P x Q = 59.375 %).

October 14, 2026¤

add: ChangePointEvents (events/quality/change_point.py) -- offline change-point detection: exact PELT (Killick et al. 2012) and binary segmentation in plain numpy, Gaussian mean or mean+variance costs, BIC penalty; detect_change_points (point) and segment_statistics (interval). add: MultivariateSPCEvents (events/quality/multivariate_spc.py) -- Hotelling T² with Phase I (beta) and Phase II (F) limits on a reference period, per-variable contributions, and out-of-control runs with the top contributor. Signals aligned backward with an optional max_gap. fix: Gauge R&R follows the AIAG average-and-range method: AV subtracts the repeatability share EV^2/(nr) (a negative radicand gives AV = 0), and AV and PV use K2/K3 = 1/d2 (g = 1) instead of the large-sample d2. Before, AV and PV were overstated (2 appraisers: by 25 %), and so were GRR and %GRR. Checked against the AIAG worksheet constants. add: EnergyPerformanceIndicatorEvents.enpi_vs_baseline(baseline="regression") -- ISO 50006 energy baseline energy = a + b*units fitted on a fixed baseline period (baseline_period= or the first baseline_window windows); adds expected_energy_kwh and energy_savings_kwh. Default unchanged. docs: every page now shows only names that exist (NumericFilter, OutlierDetection, MetadataLoader, S3ProxyParquetLoader, NumericCalc and wrong module paths replaced with the real API); tests/docs checks every ts_shape import and attribute in the docs' code blocks. CI builds the docs with mkdocs build --strict (38 warnings fixed). Python 3.14 classifier; README and the development guide describe the real CI/release pipeline. fix: eventlog static-shape event ids hashed the export time, so re-exporting the same detector output gave different ocel:eid values; they are now stable (ported from the open PR #60). add: ts_shape.eventlog.describe("Class.method"), has_override() and clear_overrides(); severity is coerced to the info/warn/critical vocabulary (low/minor -> info, medium/major/warning -> warn, high/alarm/error -> critical; anything else warns and becomes ). add: ts_shape.signals -- SignalSpec / SignalSpecs (dict/YAML round trip), infer_specs() with per-field reasons, and spec-driven primitives: intervals, increments, per_window, align, windows, shift_windows. add: ts_shape.profile(df) -- per-signal data-quality and semantics report (gaps, resets, duplicates, NaT, missing values, mixed value columns, change-encoded and possibly-stuck signals) with .summary() / .issues(). add: recovered unmerged work from earlier sessions: AssetHealthIndexEvents, ProductionScheduleAdherenceEvents, RootCauseCorrelationEvents (Aug 10 entry below), PowerIntegrator (Aug 20 entry below), and the four inline-metrology quality modules MeasurementUncertaintyEvents (GUM type A/B, combined/expanded uncertainty, budget), EnvironmentalCompensationEvents (correlation, sensitivity, compensation, exceedance), CalibrationValidationEvents (linearity, calibration curve, recalibration need, stability) and SamplingResolutionEvents (quantization, effective resolution, aliasing, jitter). All are registered in the taxonomy and covered by the invariant harness (260 methods). fix: PowerIntegrator daily windows on DST days (23 h / 25 h) and AssetHealthIndexEvents.maintenance_forecast timezone. build: lean core install (pandas, numpy, scipy); loader backends are the extras [s3], [azure], [api], [sql], [postgres], [yaml], [all]. add: specs= on MachineStateEvents and DowntimeTracking (defaults follow the signal's spec; explicit arguments win). add: registry-wide invariant harness (tests/invariants) pinned to a ratchet baseline, and hypothesis property tests for the primitives. fix: 36 frequency defaults such as window="5m" crashed resample on pandas 3 ('m' is no longer an offset); now "5min". CycleExtractor durations accept any pandas duration string. fix: OEECalculator daily summaries are tz-aware with real day lengths (23 h / 25 h on DST days); BottleneckDetectionEvents, warmup_consistency and demand spikes keep the timezone. fix: MachineStateEvents accepts an empty frame; ToleranceDeviationEvents groups events on the actual signal only (other uuids split or merged them).

October 13, 2026¤

Weekly screen of the non-production packs (see docs/gap_screening_other_packs.md). fix: CycleExtractor -- every process_* method returned cycle_end=NaT and is_complete=False; cycles now open on rising edges / step entries, never close at themselves, keep a tz-aware systime and ignore other uuids. fix: ToleranceDeviationEvents applied each measurement the next (future) tolerance; capability indices use the latest limits, a single tolerance is one-sided, and one measurement raises. fix: ControlLoopHealthEvents / DisturbanceRecoveryEvents align PV with the setpoint in force (backward as-of) instead of SP-left / nearest. fix: FailurePredictionEvents.remaining_useful_life no longer reports RUL 0 for a trend moving away from the threshold; NaN samples are skipped. fix: LeadTimeAnalysisEvents matches deliveries by order id when present. fix: EnergyEfficiencyEvents.efficiency_comparison summed raw counter readings. fix: tz-aware systime is preserved across quality/engineering/maintenance/ supplychain events (no more naive-UTC .values); DateTimeFilter accepts naive bounds on tz-aware columns. fix: MaterialBalanceEvents reported a zero-input window with output as balanced. fix: OutlierDetectionEvents -- zscore ignores NaN, MAD=0 falls back to mean absolute deviation, IsolationForest skips NaN. fix: SPC CUSUM with sigma 0/NaN returns no shifts (warning); steady-state windows with <2 samples are no longer "steady"; demand empty periods are not zero demand and calendar periods work in seasonality_summary. fix: setpoint oscillation crossings through an exact zero counted once; detect_startup_adaptive no longer flags a flat idle signal; track_startup_phases advances through non-overlapping phases. add: opt-in handle_resets (energy per-unit/EnPI/carbon/SEC, TimeGroupedStatistics 'diff'), handle_refills (inventory consumption_rate), interval_end="next_change" (threshold, signal quality, degradation, vibration, steady state, segments, low stock, correlation breakdown, time_above_threshold), time_weighted (material balance, idle energy), max_gap (error_integrals), missing_as_zero (material balance), group_by_uuid (outlier detection, boolean/string edge filters, TimeGroupedStatistics), inclusive (DateTimeFilter), ambiguous/nonexistent (TimezoneShift). Defaults unchanged. add: helpers utils.counters.counter_per_window, utils.intervals.interval_end_times, utils.time_weighted.time_weighted_resample. add: Base warns (DataQualityWarning) on NaT timestamps. fix: data_completeness / coverage_by_period use each window's real length (DST days are 23 h / 25 h); auto min_gap ignores duplicate timestamps. fix: lag_correlation / rolling_correlation lag and window in time on the regular grid instead of rows after dropna(). fix: detect_flatline starts a run at its first stuck sample; opt-in interval_end="next_change" for deadband historians. fix: GaugeRepeatabilityEvents.repeatability uses within operator x part ranges when operator_column is set. fix: overshoot_metrics undershoot is measured after the setpoint is reached. add: detect_warmup / detect_cooldown max_pause; detect_startup_adaptive baseline_window is now honoured (default None keeps the sample lookback).

August 20, 2026¤

add: PowerIntegrator (ts_shape.transform.calculator.power_integration) -- the missing kW -> kWh step. The events.energy detectors aggregate their input with sum(), i.e. they assume energy deltas in kWh; feeding an instantaneous active-power tag (e.g. *.Total_Active_Power-kW) in directly produced a number that scaled with the logging rate rather than with consumption, and a plain mean() was a sample-count average that over-weighted bursts. PowerIntegrator.energy_by_window integrates properly -- each sample weighted by how long it was valid, segments split at window boundaries (a hold from 00:55 to 01:05 books 5 minutes to each hour), locf or linear interpolation, max_gap to drop logging outages instead of billing phantom energy, power_unit for W/kW/MW tags, and per-signal integration before summing (energy adds across machines, power does not). Reports coverage per window and omits unmeasured windows rather than reporting them as 0 kWh. to_energy_deltas emits the result in the standard ts-shape schema so the energy pack can consume it; segment_energy exposes the per-sample audit trail. Exported at the top level as ts_shape.PowerIntegrator.

August 10, 2026¤

add: AssetHealthIndexEvents (events.maintenance.asset_health_index) -- fuses several degradation signals into one weighted 0-100 asset health index using the same drift/variance/trend penalty model as DegradationDetectionEvents.health_score. health_index reports the dominant failure mode and a confidence level (share of configured signal weight that had data); health_events emits warning/critical crossings; signal_contributions ranks the signals by the health they cost the asset; maintenance_forecast extrapolates to a critical threshold and withholds a date when the trend fit is weaker than min_confidence. Closes gap 3.1 of the manufacturing-operations research doc. add: ProductionScheduleAdherenceEvents (events.production.schedule_adherence) -- joins a planned schedule (start/end/planned_qty/order_id) against actual production from a monotonic counter. adherence_by_period reports adherence %, deviation units, an ahead/on_track/behind/critical_behind band, and the units/hour needed to recover in the time left in the period; deviation_events emits the breaches; adherence_summary rolls the horizon up weighted by planned quantity. Actuals are reset-aware by default (handle_resets=True). add: RootCauseCorrelationEvents (events.correlation.root_cause_correlation) -- directed, event-driven counterpart to AnomalyCorrelationEvents: takes another detector's events and ranks candidate signals by lagged correlation with the event onsets. Only non-negative lags are searched (a cause precedes its effect) and the winning lag's p-value is Bonferroni-corrected for the lag scan, so noise scanned over many lags is not promoted to a root cause. rank_causes / top_cause / lag_profile.

July 31, 2026¤

add: OEECalculator.calculate_oee now threads handle_resets to its performance and quality components and max_gap to its availability/performance components. Previously the top-level OEE could not benefit from reset handling, so a day with a counter reset silently dragged OEE toward zero; and availability booked a logging/overnight gap (last state = running) as run time. calculate_availability and calculate_performance gained a max_gap kwarg. Output schema unchanged. add: opt-in max_gap on RuntimeAccountingEvents.runtime_summary, runtime_per_window, and operating_hours_meter -- a gap to the next sample longer than max_gap is treated as a logging outage and excluded, so it no longer inflates run time, utilization, or the hour meter. fix: LineThroughputEvents.throughput_oee honored the documented availability_threshold parameter, which was previously accepted but ignored. A window now counts as available when its part count reaches availability_threshold x target_rate; the new default 0.0 reproduces the old "produced anything" behaviour. throughput_oee also gained handle_resets (threaded to count_parts). add: opt-in infer_dwell_from_next on the traceability timelines (OrderTraceabilityEvents.build_timeline / current_status / station_dwell_statistics, RoutingTraceabilityEvents.build_routing_timeline / station_statistics, MultiProcessTraceabilityEvents.build_timeline / station_statistics). A station that logs an identifier once on arrival otherwise reports a per-station dwell of 0; when set, each visit's end is the identifier's next station arrival (in multi_process, only for sequential visits -- parallel/overlapping visits keep their own span). Default unchanged. add: opt-in production_day extended to the remaining shift-grouping methods that share _assign_shift -- ScrapTracking.scrap_by_shift, ReworkTracking (rework_by_shift, rework_rate), QualityTracking (nok_by_shift, daily_quality_summary), OperatorPerformanceTracking.production_by_operator -- so an overnight shift is one contiguous (date, shift) group. Default (raw calendar date) unchanged. add: opt-in max_gap on DowntimeTracking.downtime_by_shift / availability_trend and max_cycle_gap on CycleTimeTracking.cycle_time_by_part and PerformanceLossTracking (performance_by_shift, slow_periods, performance_trend). A duration taken as next-time minus time otherwise bridges logging gaps and stoppages: a logger outage is booked as uptime, and a lunch break becomes one giant "cycle" that reads as a huge speed loss. Durations above the cap are excluded as "no data". Default (None) unchanged. add: opt-in time_weighted on BottleneckDetectionEvents.station_utilization (and detect_bottleneck / shifting_bottleneck / throughput_constraint_summary) and DutyCycleEvents.duty_cycle_per_window. resample().mean() averages sample counts, so on change-encoded/irregular signals a station up all hour but logged once reads 50-100% by row count; time_weighted weights each sample by the gap to the next sample. Default (sample mean) unchanged. fix: LineThroughputEvents.cycle_quality_check returned inf/NaN deviations when the expected cycle time was zero (explicit, or a degenerate zero median); it now returns the typed empty frame. add: ts_shape.utils.shifts (assign_shift, production_dates) -- shared shift assignment plus a "production day" that attributes an overnight shift's post-midnight readings to the shift's start date. Grouping a night shift (22:00->06:00) by raw calendar date splits it across two dates and, within a date, spans the whole day so last - first sweeps in other shifts' output (a night shift could report ~750% of target). add: opt-in production_day=True on TargetTracking.compare_to_target, ShiftReporting.shift_production, and ShiftHandover.generate_report so overnight shifts group as one contiguous interval. Default (calendar date) unchanged. add: opt-in require_all_stations=True on LineBalancingEvents.balance_metrics so a fully stopped station stays in the denominator (a dead station previously read as a perfectly balanced line); adds a stations_missing column. add: opt-in count_initial_active=False on AlarmManagementEvents.alarm_frequency to ignore an alarm already active at the start of the data window. add: ts_shape.utils.intervals.state_intervals -- shared helper that collapses a state signal into intervals and closes each one at the next transition when interval_end="next_change". The previous "end at the last sample carrying the state" logic collapses to zero duration on change-encoded (is_delta) signals -- one row per transition -- so downtime, micro-stop and duty-cycle analyses silently reported nothing on the library's normal data shape. add: opt-in interval_end="next_change" (with an optional data_end bound for the final open interval) on MachineStateEvents.detect_run_idle / state_quality_metrics and LongDowntimeEvents.detect_long_downtime, and as a constructor option on MicroStopEvents and DutyCycleEvents. Default ("last_sample") is unchanged. On change-encoded signals this recovers micro-stop lost time, multi-hour downtimes, and on/off durations that previously read as zero. (Traceability dwell shares the collapse but has distinct cross-station semantics and is a separate follow-up.) add: ts_shape.utils.counters (counter_quantity, counter_increments, count_resets) -- shared reset-aware handling for monotonic production counters that reset to zero at a shift/part change or PLC restart. A naive last - first loses all production in a window where a reset happened. add: opt-in handle_resets=True across the production pack so the reset-aware behaviour shipped in PartProductionTracking is available everywhere a quantity is derived from a counter: OEECalculator (calculate_performance, calculate_quality), LineThroughputEvents.count_parts, TargetTracking, ScrapTracking, ReworkTracking, QualityTracking, BatchTrackingEvents, OperatorPerformanceTracking, ContinuousProcessAlignment.segment_by_cut, ShiftReporting, ShiftHandover, and PeriodSummary. Default behaviour and column sets are unchanged; when enabled the result gains a resets column. For the by-reason / by-part methods this also corrects the over-count that last - first produces when categories alternate over a non-contiguous group. fix: DowntimeTracking.downtime_by_reason booked running time as downtime (it diffed timestamps after filtering to stopped rows, so a stop lasted until the next stop). Duration is now computed on the full state timeline before filtering, mirroring downtime_by_shift. fix: QualityTracking.daily_quality_summary returned NaN rates for a zero-total day (0/0); both rate divisions are now guarded to 0.0. fix: LineThroughputEvents.throughput_oee produced NaN/inf performance when the target rate was zero (flat counter or explicit 0); it now reports 0. fix: ShiftReporting.shift_targets produced inf achievement_pct for a zero target; now guarded to 0.0, matching ShiftHandover. add: ChangeoverEvents.detect_changeover gained include_initial (default True preserves the current behaviour of emitting the first reading; pass False to report only real value changes and drop the synthetic leading event). docs: docs/production_gap_screening.md -- a full functional-gap screen of the production pack, with the remaining themes (interval-duration on change-encoded signals, gap-spanning durations, time-weighted utilisation, overnight-shift attribution) lined out as scoped follow-ups.

June 2, 2026¤

changed: event-log output now trims entirely-empty extra columns. The 9 canonical core columns (ocel:eid, ocel:activity, ocel:timestamp, ts_shape:start_timestamp, ts_shape:duration_s, ts_shape:detector, ts_shape:pack, ts_shape:severity, ts_shape:value) are always emitted, so every event log keeps an identical append-friendly core schema; per-detector extras (: passthroughs, standard-attr extensions) are dropped when all-empty instead of shipped full of NaN. add: align_columns(logs) -- reindex multiple EventLogs' events tables to their shared column union (core first, extras sorted) so each frame exposes an identical column set before appending/stacking. concat(...) already unions columns on merge; this is for callers stacking frames themselves. changed: event-log exporters renamed for a consistent to_event_log family: to_flat_df -> to_event_log_xes, to_ocel_tables -> to_event_log_ocel. The old names remain as deprecated aliases (DeprecationWarning) for back-compat.

May 20, 2026¤

add: Pipeline -- the single declarative orchestrator for ts-shape. Chains transform and detector steps into one reusable definition: .transform() steps replace the working signal; .detect() steps store named event results. Supports $input/$prev sentinels for multi-DataFrame wiring, run_steps() for intermediates, describe() for previews, and PipelineResult.to_event_log() for combined OCEL export. BREAKING: removed FeaturePipeline (features.segment_analysis.feature_pipeline); Pipeline replaces it. Migration: FeaturePipeline(df)...run() becomes Pipeline()...run(df); .add_step(Cls.method, **kw) and .add_instance_step(Cls, call='method', **kw) both become .transform(Cls, 'method', **kw); .add_lambda_step(fn) becomes .transform(fn). $input/$prev sentinels and run_steps() are unchanged. add: UnitConverter -- engineering unit conversion (transform), a thin wrapper around the pint library. Optional extra: pip install ts-shape[units]. add: RuntimeAccountingEvents -- operating-hours accounting (total run time, start count, longest run, utilization, per-window runtime, hour-meter). add: LineBalancingEvents -- line balancing & takt analysis (station cycle times, balance efficiency/delay, smoothness index, theoretical minimum stations, Yamazumi station-loading table). add: FlowMetricsEvents -- flow analytics (time-weighted WIP, throughput, FIFO lead time, Little's Law consistency check, Process Cycle Efficiency). add: ts_shape.make_timeseries() -- public synthetic-data generator for trying detectors and transforms without real data or loaders. add: ts_shape.list_detectors() -- programmatic catalog of every top-level class, grouped by pack/category. add: Base.repr -- detector and instance classes now print a useful summary (row count + configured uuid/value_column). changed: OutlierDetectionEvents emits the canonical point shape (systime, uuid, source_uuid) via events/_output.py -- completes the May 14 output standardization. uuid carries the event id, source_uuid the source signal. changed: event detectors validate their configured UUID up front (Base._validate_uuid) -- a typo'd UUID now raises a clear error listing the available UUIDs instead of silently returning empty results. fix: DatapointAPI HTTP requests now send a timeout (default 30s) so an unresponsive server can no longer hang the loader. fix: TimescaleDBDataAccess uses bound SQL parameters instead of f-string interpolation. fix: CycleExtractor uses Base's sorted, defensive copy -- it no longer mutates the caller's DataFrame. fix: README quick-start and pack examples corrected to match real constructor signatures (SPC, ToleranceDeviationEvents, DataIntegratorHybrid, TimeGroupedStatistics).

May 14, 2026¤

BREAKING: event-detector outputs standardized across all packs (quality, production, engineering, maintenance, supplychain, energy, correlation). Every public DataFrame-returning method now emits one of three canonical shapes: point (systime), interval (start, end, duration_seconds), or summary (start, end, duration_seconds + aggregate columns).

Column renames applied uniformly: start_time, gap_start, window_start, period_start, disturbance_start -> start end_time, gap_end, window_end, period_end, disturbance_end -> end severity_score, severity_level -> severity OEECalculator: date -> start + end + duration_seconds (86400)

New helpers in src/ts_shape/events/_output.py (empty_event_df, finalize_point_df, finalize_interval_df, finalize_summary_df) define the canonical column constants and empty-frame schema.

ts_shape.eventlog.adapters.adapt no longer probes legacy column name variants -- it expects the canonical names. The taxonomy registry has been updated (severity_field="severity"). See docs/guides/eventlog.md for the simplified shape table.

Downstream code asserting old column names must be updated.

Sep 09, 2025¤

add: Azure blob storage container loader add: Metadata JSON loader added changed: development guide

Apr 06, 2025¤

add: quickstart guide added to docs

Dec 26, 2024¤

add: mkdocs material deployment with gh actions

Dec 25, 2024¤

add: pdoc docs exchanged with mkdocs material autodoc

Dec 23, 2024¤

add: library rename add: library structure change. loader, transform, feature, context, events

Dec 20, 2024¤

fix: closes #7

Nov 16, 2024¤

add: dev state docs for combine/integrator.py add: dev state for combine/integrator.py add: metadata loader improved

Nov 4, 2024¤

add: stats classes improved + feature table class added

Oct 29, 2024¤

add: timescaledb loader adjusted

Oct 28, 2024¤

add: loader classes adjusted add: classes for timestamp_converter added add: classes for s3, timescaledb, timezone_shift added

Oct 27, 2024¤

add: docs for time_stats added add: time_stats for numeric value columns added

Sep 11, 2024¤

add: methods refactored to execute without an instance

Sep 9, 2024¤

add: cycle methods refined and splitted to cycle processor and extractor

Sep 8, 2024¤

add: cycle method and metadata loader including tests for numeric filters add: additional methods added

Aug 25, 2024¤

fix: docs re-created fix: docs add: parquet loader, timestamp, string, numeric and boolean stats methods

May 4, 2024¤

change: typings added, first test added change: package folder moved init: pypi package structure for timeseries-shaper / internal project for my master thesis