Changelog¶
This project follows semantic versioning after 1.0. During the 0.x beta, minor releases may
change documented APIs with the notice and deprecation process in docs/compatibility.md.
Unreleased¶
- Fixed the release workflow's final step, which attaches the distributions and
SHA256SUMSto the GitHub release:gh release uploadnow names the repository, because the publish job has no checkout. The0.1.0upload to PyPI itself was unaffected. - Made the README's links and images absolute so the PyPI project page renders, and added a test that rejects relative README targets.
0.1.0¶
First public release. It includes everything in the earlier release candidates 0.1.0rc1
through 0.1.0rc5, which were not published to PyPI and are kept below as history.
- Every built-in operator is now labeled Selection, Annotation, or Aggregation in
docs/operators.mdanddocs/operator-inventory.md, by its primary effect on the segment pool. No built-in operator is Aggregation yet — a confirmed gap (reducing a per-window feature to a per-group rollup), not an oversight; seeaction-state-consistency.md. - Renamed
gameplay.slam_pipelinetogameplay.slam_reconstruct(groups withslam_quality/slam_motion_diversityunder oneslam_prefix for discoverability). Clean rename, no compatibility alias. ExtractedCollisionMechanics's per-tick velocity/turn-rate derivation from a private, untested function into a public, directly testedkuration.gameplay.collision.kinematics.extract_kinematics— the one part of its fused per-tick scan/classify loop that is independently reusable; the gating and raycast classification stages remain fused, as doesDirectionalCollisionAnalyzer's unrelated expected-velocity-from-ramp-model computation. - Added
Segment.records: dict[str, list], a non-scalar counterpart toSegment.featuresfor transforms measuring several discrete per-instance events within a window.PixelShiftnow emits its per-press instances there instead of discarding them after collapsing to scalars.action_state_consistencyis rehosted asActionStateAnomalyScorer, aSegmentScorerreading pixel-shift's own records instead of redundantly re-deriving them from raw frames — it scores per window, not per whole clip, since no built-in aggregation operator exists yet to reconstruct the old per-clip verdict (see above). Dataset-mode auditing (check_dataset) never shared computation with a live pixel-shift transform and is unaffected; only the tick-stream-driven analyzer path (the actual redundant-computation bug) is retired. - Eliminated the standalone
kuration-aipackage. Its three curation recipes (BalancedSelector,RareEventCoverage,DiverseSubset) and config-drivenrun/plan/describe/register_operation_typerunner are now first-class SDK components underkuration.selection, each also registered as aPipelineoperator (kuration/balanced-selector,kuration/rare-event-coverage,kuration/diverse-subset).kuration-aiis preserved, unmodified, on thefeature/kuration-ai-legacybranch. - Development builds now use the distinct
0.1.0rc5.dev0identity instead of reusing the prior0.1.0rc4candidate identity.ARTIFACT_FORMAT_VERSIONis1.2for the corrected bounded/materialized uniform-bin ordering, experiment-arm tag isolation, and zero tag-coverage-floor semantics described below. - Raised the minimum versions of scikit-learn, PyArrow, protobuf, PyTorch/TorchVision, Ray, tqdm, and Pillow past known-vulnerable historical floors; the minimum-dependency CI lane now exercises those security-supported baselines.
- Dataset publication is no-clobber by default across pipeline, classic, job/CLI, and import
paths.
force=True(orkur-curate --force) explicitly replaces a destination;resume=Trueremains a separate, fingerprint-matched hours-run intent. Selection, source-contract, container-dependency, and output-memory preflights finish before invalidating an old commit; one writer lease prevents concurrent publishers from interleaving. Resume markers are now commit-checksummed, non-resumable replacements remove stale markers, and bounded checkpoints are namespaced by run fingerprint. - Fixed selection correctness across execution modes: bounded uniform-bin RNG order now matches
canonical materialized order, predicates remain hard exclusions through tag coverage,
fractional tag floors round up, experiment arms no longer inherit unrelated tag vocabularies,
min_tag_frac=0is a true no-op, and Python-equal group/tag values have the same meaning in memory and SQLite-backed fills. - Persisted reuse now fails closed unless inputs have adapter, local-content, or immutable remote version identities. Readers pin one exact commit generation for each operation, validate manifest modality contracts against the committed output config, and reject local shard symlinks and non-regular files. Source references and persisted skip diagnostics no longer publish credentials or host-local paths.
- Smart imports now validate and consume one private local source snapshot: POSIX ancestry is traversed through no-follow directory descriptors, array/tick publication never reopens the caller pathname, and directory stores are copied descriptor-relatively. Generic remote imports fail closed because an unconditioned fsspec read cannot be bound to a separately reported object generation; download the exact immutable generation locally first. Smart import also fails before source inspection on platforms without POSIX descriptor-relative open support.
on_error="skip"now applies consistently to transform and scorer second-read failures as well as the feature pass; failed sources are removed as a unit, mutable transform state is reset before continuing, and total failure remains loud.- Tightened validation at the boundary:
speedrequires a declared sample rate, numeric filter literals must be finite, bitmask values must be positive exact integers, and mixed-case.parquetsuffixes follow one detection/preflight/read path. - Analyzers are pipeline operations. New
Pipeline.analyze(name, parameters=None, *, mode=None, inputs=None, batch_size=None, analyzer=None, **options)terminal drives a registered stateful analyzer with no job spec and no CLI. On anyinput(...)pipeline it drives a new optionaladd_batch(batch, ctx)hook (StreamAnalyzer) over the segmented tick stream through the same bounded batch/media-decode machinery batch transforms use (transforms.build_batch, one decode path, per-input lookbehind/lookahead,ctx.input_token,ctx.valid_steps) — a single pass with one batch resident, so it works understreaming=True. On an artifact-backed pipeline it drivescheck_datasetand returns exactly whatrun_dataset_analyzer()returns. Analyzers declarefield:/media:inputs (plus optional per-input boundary counts) at registration, validated there and bykur-plugin-check; unknown analyzers, a missing hook for the resolved mode, and a pool that measured zero segments all raise.run_stream_analyzer()andStreamAnalyzerare exported for callers driving an analyzer outside the pipeline API. - The built-in
aintropy/action-state-consistencyanalyzer now runs on both modes. Its tick-stream path declares the same input contract asaintropy/pixel-shiftand measures in real source frames, so the documented(source_id, control, cell_key, frame)de-duplication of one press seen by overlapping windows holds (cross_window_dedup: true) — the guarantee dataset mode has to give up (frame_space: "shard-concatenation"). - New
Pipeline.check(policy=None, *, verify=False, **expectations)— the pipeline-API equivalent ofkur-check --policy: it merges.expect(...), a policy mapping, and keywords, then evaluates them without raising against an artifact inspection (artifact-backed pipelines) or a bounded input preview.CuratedDatasetAdapter.datasets()is the new adapter seam that lets a pipeline reach artifact-level hooks at all. Pipeline.stats(**kwargs)now forwards every keywordkuration.stats()accepts (includingprogress) instead of re-declaring a narrower subset that could drift.- Batch-transform inputs are now roles rather than fixed batch keys.
TransformContextcarriesinputs(declared role → resolved token, in declaration order) andinput_token(role), so a transform used with a per-useinputs=remapping addresses the batch it was actually given instead of failing mid-run on a hardcoded registration token. A remapping must supply exactly one token per role, of the same kind, and per-inputmedia_requirementsare matched by role; all three are validated while the pipeline is built. The bundledaintropy/pixel-shifttransform now resolves its frames/actions inputs (and its mediacolor_space) this way. lookbehind/lookaheadmay be declared per input (lookbehind={"field:action": 1}) instead of as one count shared by every input, so a transform no longer pays to extract — or, for media, decode — boundary context it never reads.aintropy/pixel-shiftdeclares its single lookbehind row on the action input only, removing one video-frame decode per segment.- Every batch transform now receives per-row valid timestep counts (
ctx.valid_stepsand thevalid_stepsbatch entry).field:inputs are(B,T,E,D)arrays NaN-padded to the widest extent in the batch — a contract change from the earlier(B,T)stacking, which raised on a ragged batch instead of padding it — and the counts make that padding observable, so a transform cannot silently average pad cells; previously onlyownership="rightmost-start"transforms received any length information. pixel_shiftgained a{control}_shift_measured(0/1) feature. The transform contract admits only finite scalars, so an untested control'sshift_min/max/meanmust report some number; the flag makes "no instance was measured" filterable (.filter("w_shift_measured", ">=", 1)) instead of indistinguishable from a real zero-shift measurement.pixel_shift.iter_instances()now validates its own arrays (passvalidated=Truefor arrays already returned byvalidate_segment_inputs).- The action-state analyzer accepts NumPy integer segment indexes (normalizing them to
int), and itscheck_datasetno longer presents synthetic offsets as source frames: results reportframe_space: "shard-concatenation", per-shardshard_ranges, andcross_shard_dedup: false, with the same caveat printed in the report. Manifest entries carry no source start offset, so cross-shard de-duplication of overlapping curated spans is documented as unavailable in dataset mode instead of silently lost. - Gameplay video contact sheets label a frame index as
frame Ninstead of formatting it as"{:.2f}s"when a source exposes neither a duration nor an average frame rate. - Bumped
ARTIFACT_FORMAT_VERSIONto1.1for two DSL semantic changes and recorded them in a compat table (ARTIFACT_SEMANTIC_CHANGESinkuration.core.versioning):dispersionandmin_pair_distnow use every declared position dimension (1.0used only the first two), andscope: per_entity_meanis now honored on categorical fields (1.0silently pooled them). Both change which segments get selected on 3D-position or per-entity-categorical data, sokur-migratenow prints the notes for the versions a document has not seen while it migrates it.migration_notes()/document_migration_notes()expose the same table programmatically. - Registering a compositional operator whose method name is already a real
Pipelineattribute (report,window,filter,schema, ...) now fails loudly at registration and inkur-plugin-check, naming the collision and asking for a rename. Python resolves the attribute before__getattr__, so such an operator was silently shadowed and unreachable. The reserved set is derived from thePipelineclass itself. - An un-namespaced operator now keeps its own method spelling when a plugin registers the same
local name: a spelling that is a component's complete name outranks the same spelling used as a
namespaced component's shorthand (
smoothvsacme/smooth, stillacme__smooth()). An ambiguity error now only suggests spellings that actually resolve, falling back toapply("<name>")when a component has no unique method spelling left. - Added two pipeline-only public-data walkthroughs.
examples/public_data/ett.pycurates real hourly electricity-transformer telemetry, andperson_activity.pycurates 25 real wearable-sensor recordings with four tags as the entity axis, a tag-coverage floor that keeps rare activities, and source-level splits stratified by person. Both take a local path, fetch the data with--download, or run offline against synthetic stand-ins with--demo; each ships a provenance/licensing note and the equivalent command-line session. - Simplified the numbered examples.
01is now the genuine five-minute start —input()over a folder of CSVs with everything inferred — and02/03drop their hand-rolled adapter classes in favour of passing{source_id: ticks}straight toinput(). - Fixed
dataset_reportcrashing on a metric whose values differ only at float-noise scale. NumPy widens the histogram range for exactly-constant data but raises "Too many bins for data range" just below that, which took down.review()andkur-reportfor a near-flat field; such a metric now reports as the flat distribution it is. kur-initnow scaffoldsspan_stepsalongside its hours budget. Without a span the budget admits whole tracks, so a single long recording was emitted in full regardless of--train-hours.- Added a
kurdispatcher so every command is reachable askur <command>alongside its ownkur-<command>script, withkur --help/--listandkur completion bash|zsh|fish. Subcommands contributed by installed plugin packages are discovered through their console script entry points, so no domain is named in the core dispatcher. - Added
kur-infer,kur-init, andkur-preview, closing the gap before a job spec exists.kur-inferemits the inferred schema (referenceable from a job by path);kur-initscaffolds a whole job and resolves it before writing, so what it emits is a jobkur-validateaccepts;kur-previewdecodes a bounded prefix of the sources and reports field ranges, missingness, and example ticks. - Added
kur-statsandkur-exporton the artifact side.kur-statsexposes the existing unifiedstats()report — including plugin-contributed sections — to the shell, andkur-exportwrites shards as npz/npy/parquet with anexport_index.jsonpreserving the manifest metadata that bare arrays lose. - Added
kur-checkpoint list|verify|clearfor stage checkpoint directories. Verification reads committed metadata instead of reconstructing the run'sCheckpointIdentity, so a damaged commit is detectable from the checkpoint tree alone;clearrequires--yesand supports--attempts-only. - Added
--review,--review-json, and--review-htmltokur-curate, surfacing the hours-budget admission review from the run's recorded decisions without a second scoring pass. - Added
kur-importandimport_dataset()with confidence-based registered-adapter detection. NPZ, HDF5, and Zarr use lossless tensor hooks; CSV, JSONL, and single/partitioned Parquet use ordinary schema inference and canonical ticks. Plugin adapters can advertise detection and raw-array import hooks. Imports default to source-aligned shards and publish the same checksummed transactional artifacts consumed by inspection, analyzers, and loaders. - Added artifact-level analyzer execution to
kur-check, with separate JSON construction parameters and dataset options, composable quality-gate output, and exit-code-2 verdicts. Action-state consistency can now read configurable frame/action modalities from curated shards, while split leakage can audit assignments directly from a dataset manifest. - Added unified lifecycle stats for pipelines, curated selections, write results, and existing
dataset artifacts. Reports render directly in notebooks, can be saved as standalone HTML, and
offer optional Matplotlib plots through the
statsextra; artifact stats inspect the actual emitted, padding-trimmed arrays. Importing the gameplay domain now enriches the same report with video, action, and SLAM signals and a gameplay plot; synchronized video comparison, automatic Jupyter/terminal progress selection, and a model-free JupyterLab example complete the end-user workflow. Reports discover their available plots and evidence modes, choose an applicable domain plot automatically, and expose bounded selected/rejected/strongest/weakest examples; live gameplay reports add frame strips, actions, and SLAM diagnostics without placing media in serialized report data. - Added
kuration.coreandkuration.gameplaydomain surfaces. Pixel shift, action-state consistency, and SLAM now ship together in the SDK wheel instead of separate first-party plugin distributions; OpenCV, Torch, FAISS, and related runtimes remain extras. - Physically moved the generic SDK implementation under
kuration.coreand madekuration.gameplaythe only maintained domain package. Direct implementation imports such askuration.pipelinenow usekuration.core.pipeline; package-level imports such asfrom kuration import Pipelineremain available. Removed the former gameplay compatibility packages, and nested Depth Anything privately under gameplay SLAM. - Integrated the native
kuration.gameplay.slam.SLAMReconstructorandslam_pipeline()workflow for optional video/frame reconstruction, stable model/config provenance, resumable portable exports, trajectory quality and diversity curation, point-cloud reduction, preflight, andkur-slam. Precomputed manifests remain a lightweight NumPy-only SDK input; global model execution is intentionally separate from bounded compositional operators.
0.1.0rc4¶
- Added a discoverable
analyzerregistry kind for user-owned capabilities that aggregate across segments, withregister_analyzer(),get_analyzer(), and CLI discovery. The action-state consistency plugin now registers its real clip-level analyzer instead of an unrelated stateless compliance component. A dependency-freekuration/split-leakageanalyzer audits existing source and group assignments across dataset splits. - Corrected pipeline and bounded execution around duplicate sources, exact vector widths, registered-metric transform dependencies, cross-kind feature collisions, scorer parameters and registry lookup, callable metric overlays, test-split validation, and checkpoint partition identity. The same validation now applies consistently at direct public execution boundaries.
- Artifact readers now verify recorded shard size and SHA-256 by default, including
iter_shards(),read_shard_arrays(),ShardDataset, and curated-dataset adapters. Passverify=Falseonly for explicitly trusted artifacts. Commit sidecars, rebased legacy paths, split names, and shard paths are validated before reads, preventing traversal and stale or corrupted shard reuse. - Made shard filenames and manifest entity IDs type-preserving so values such as integer
1and string"1"cannot overwrite each other. Shard writing now rejects non-finite or extension object IDs that have no canonical value identity instead of relying on unsafe string or pickle representations. - Fixed adapter and media correctness for large integer timestamps, missing categorical values, Parquet dataset glob preflight and source fingerprints, Arrow chunk/batch ingestion, duplicate columnar bin names, joined-media fingerprints, multi-video frame rate and shape validation, and finite ordered timestamp alignment.
- Tightened registry and plugin contracts: malformed targets and true no-op entry points fail
transactionally with persistent diagnostics; pre-imported package-owned registrations remain
valid; nested parameter schemas are checked at registration; and
enum,const, anduniqueItemsuse JSON-type-sensitive equality rather than Python's boolean/integer aliasing. - Corrected job-versus-artifact migration classification, strict-mode
kur-explainpolicy, vector event-reduction preflight, nested non-finite review JSON conversion, group-report identity collisions, actionable video inference errors, and feature-schema drift detection. - Hardened the SLAM plugin with exact timestamp coverage and explicit point-cloud format/version validation in both manifests and NPZ artifacts.
- Added focused regression suites for the comprehensive correctness review and its independent cross-subsystem follow-up, alongside full core, plugin, typing, lint, example, and distribution build verification.
0.1.0rc3¶
- Added transactional plugin loading: failed initializers roll back registry mutations, explicit
modules fail fast, and broken ambient entry points no longer hide healthy plugins; ambient
failures remain visible through discovery CLIs,
plugin_failures(), and run provenance. - Added
kur-plugin-check, the publiccheck_plugins()API, and a one-command isolated plugin validation workflow covering dependencies, tests, lint, wheels, entry points, and descriptors. - Added typed
TransformContextboundary accessors while retaining the rc2 batch-key compatibility form, plus deterministic lookbehind/lookahead and overlapping-window ownership. - Bounded source scheduling, Ray submission, transform context memory, Hugging Face partition
behavior, and the pixel-shift radial cache; kept Arrow publication on the caller thread and
removed process-global reporting assumptions. Ray's
workersnow caps submitted tasks even whenmax_in_flightis larger. - Hardened source-ID normalization, normalized timestamp grouping, count-budget tag coverage,
remote replacement failure behavior, and unknown-total progress reporting. Direct low-level
curation calls now require non-empty string source IDs; convert
pathlib.Pathvalues withstr. - Binning now fails explicitly when any candidate lacks a requested axis feature instead of silently treating the missing metric as zero.
- Added cross-mode determinism conformance tests spanning serial/parallel, streaming/materialized, bounded/reference, and optional Ray execution.
- Isolated every repository plugin in CI and added exact-CI-artifact plugin publication with metadata, hash, wheel-content, dependency, and installed-discovery checks.
- Corrected affected documentation claims and added regression coverage for realistic failure, boundary, overlap, retry, packaging, and discovery scenarios.
- Pixel-shift radial geometry is now computed and cached as float32 (rather than float64), so measurements may differ by normal float32 rounding; the two-entry cache deliberately bounds global memory and may recompute when a process cycles through more than two resolutions.
0.1.0rc2¶
- Added integrity-aware shard resume, structured execution diagnostics, Python 3.14 and minimum-dependency CI, coverage artifacts, and real optional-backend integration tests.
- Hardened transform dispatch so implementation
TypeErrors are not mistaken for signature mismatches, and fixed transform discovery throughkur-list. - Standardized CLI failures as concise one-line errors by default while retaining full
tracebacks behind
--debug. - Hardened release automation with pinned build tools, artifact validation, CI-gated artifact promotion, platform and minimal-install smoke coverage, and trusted PyPI publishing.
- Added a runtime
kuration.__version__, a security policy, and an explicit compatibility policy. - Reworked the README and documentation around product outcomes and user journeys, added a searchable documentation site, editable diagrams, and compositional/transform-backed operator examples.
- Added support and governance guidance, contribution templates, documentation link checks, and deployment configuration for the published documentation site.
- Fixed bounded columnar execution against the declared PyArrow 15 minimum.
0.1.0rc1¶
- Initial release candidate for the schema-driven curation SDK, pipeline, job/CLI layer, versioned artifacts, extension registries, bounded execution, and optional integrations.