# Common Helper — `LightGlueRuntime`

## Purpose

Shared LightGlue inference handle. C2.5 (Re-rank) does single-pair LightGlue matching for inlier counting on K=10 candidates per frame; C3 (CrossDomainMatcher) does the heavier matching pass on the surviving N=3 candidates. Both use the same LightGlue engine; sharing the engine avoids paying the engine-build / GPU-memory cost twice.

## Used By

- C2.5 — Inlier-based Re-rank.
- C3 — Cross-domain Matcher.

## Interface (sketch)

```
class LightGlueRuntime:
    def __init__(engine_handle: EngineHandle): ...
    def match(features_a: KeypointSet, features_b: KeypointSet) -> CorrespondenceSet
    def match_batch(features_a_list, features_b_list) -> list[CorrespondenceSet]
    def descriptor_dim() -> int
```

## Implementation Notes

- Owned by the composition root; the same instance is constructor-injected into both C2.5 and C3.
- Backed by C7's `InferenceRuntime.deserialize_engine(LIGHTGLUE_ENGINE_CACHE_ENTRY)` at takeoff.
- Single CUDA stream; concurrent calls forbidden — composition root binds the runtime to the single F3 hot-path thread.

## Caveats

- The features fed in MUST come from the same backbone as the LightGlue engine was trained for (DISK in production-default; ALIKED / XFeat in alternates). Mixing backbones is a runtime error caught by the matcher's input shape check.
