Skip to content

Config refactor — migration notes

This document covers the breaking changes in the current Unreleased section of the project CHANGELOG.md (at the repository root). Each removal lists the before/after spelling so consumers can mechanically port their call sites.

DetectorPreset enum → profile= string

Before:

import locus
detector = locus.Detector(preset=locus.DetectorPreset.Standard)

After:

detector = locus.Detector(config=locus.DetectorConfig.from_profile("standard"))

Valid profile names: "standard", "grid", "high_accuracy", "max_recall_adaptive". Custom JSON profiles round-trip through DetectorConfig.from_profile_json(text).

Flat detector kwargs → nested DetectorConfig

Before:

detector = locus.Detector(
    threshold_tile_size=24,
    quad_min_edge_score=20.0,
    refinement_mode=locus.CornerRefinementMode.Erf,
)

After:

cfg = locus.DetectorConfig.from_profile("standard").model_copy(deep=True)
cfg.threshold.tile_size = 24
cfg.quad.min_edge_score = 20.0
cfg.decoder.refinement_mode = locus.CornerRefinementMode.Erf
detector = locus.Detector(config=cfg)

Detector.__init__ no longer takes the **kwargs escape hatch; unknown keywords raise TypeError. The pre-typed PyO3 enums no longer accept integer values implicitly — pass the enum instance, or the variant name as a string when editing a JSON-shaped dict.

Detector.standard_config() removed

Use locus.DetectorConfig.from_profile("standard").

locus._profile module removed

DetectorConfig lives in locus._config and is re-exported from the package root. Imports of locus._profile should switch to locus.DetectorConfig directly.

Rust DetectorConfig::*_default() removed

Before:

let cfg = locus_core::DetectorConfig::high_accuracy_default();

After:

let cfg = locus_core::DetectorConfig::from_profile("high_accuracy")?;
// or:
let cfg = locus_core::DetectorConfig::from_profile_json(include_str!("..."))?;

ConfigPreset (the test-only enum) is also gone — regression harnesses now take .with_profile(&str) / .with_profile_json(&str).

DecodeMode::Soft removed

The DecodeMode enum (Rust locus_core::config::DecodeMode and Python locus.DecodeMode) and the decode_mode field on DetectorConfig, DetectorConfigBuilder, the shipped JSON profiles, and the public Python API are gone. Hard-decision Hamming is the only path.

Migration: drop any decode_mode= argument; if you relied on DecodeMode::Soft for ICRA-style noisy decodes, accept that the detector now uses the same hard-decision path that every shipped profile already used (Soft was opt-in only on a deleted synthetic fixture).

The historical Soft-vs-Hard analysis is preserved in docs/engineering/benchmarking/lessons.md as a record-of-decisions.

PoseEstimationMode removed

The Fast / Accurate toggle is gone. The pose estimator now selects its cost surface automatically from per-corner covariance availability: image view (or external GWLF covariances) routes to weighted Mahalanobis LM with a 6×6 covariance output; no image and no covariances routes to unweighted Huber LM with no covariance.

Migration:

- detections = detector.detect(img, pose_estimation_mode=locus.PoseEstimationMode.Accurate)
+ detections = detector.detect(img)

tools/cli.py's --pose-mode flag is removed in the same change.

CornerRefinementMode::Edge removed

Edge (the gradient-peak fit_edge_line-only refiner) is gone. No shipped profile referenced it; the variant existed only as a public surface with no production consumer. The PyO3 enum is now {None=0, Erf=1, Gwlf=2} (dense integer values; the Rust enum order matches).

Migration:

- refinement_mode=locus.CornerRefinementMode.Edge
+ refinement_mode=locus.CornerRefinementMode.Erf

If you depended on Edge's specific failure-mode characteristics, note that Erf already falls back to the same gradient-peak fit (fit_edge_line) internally on sample shortfall or low contrast — choosing Erf is a strict superset of the old Edge path.

If your config used Edge simply to skip the PSF Gauss-Newton cost on high-volume scenes, None is the right choice with EdLines extraction (whose GN corners are already sub-pixel — see docs/engineering/benchmarking/lessons.md §4.1).