feat(api): explicit ?compute_trigger=true flag for time-to-detection#51
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #26.
Summary
compute_triggerquery param toPOST /predict(defaultfalse). The default serving path is unchanged — no first-crossing search, no trigger fields, byte-identical response (guarded by the exact-shape asserts intest_predict_default/test_predict_verbose).?compute_trigger=truethreads the flag throughModelRunner.predict→_predict_sync→model.predict(core already supported it since perf: make trigger_search eval-only via compute_trigger gate (closes #23) #25) and adds a top-leveltrigger_frame_index. An explicitnullmeans "searched, no crossing" — same convention asprobability.verbose=trueit also fillsdetails.decision.trigger_tube_idand per-tubedetails.tubes[].first_crossing_frame, which core already emits and the mapper previously dropped.response_model_exclude_unset=True: the new DTO fields stay unset (omitted) unless the flag is on.Design spec:
docs/specs/2026-06-11-api-compute-trigger-design.md. The ticket'spredict_sequencestep is obsolete — that function was refactored away; the runner callsmodel.predictdirectly.Request / response examples
Request body is unchanged in all cases:
Default (
POST /predict) — unchanged, fast path:{ "is_smoke": true, "probability": 0.98, "version": {"api": "0.3.0", "model": "1.2.0"} }POST /predict?compute_trigger=true— runs the first-crossing search, adds the top-level TTD field:{ "is_smoke": true, "probability": 0.98, "trigger_frame_index": 3, "version": {"api": "0.3.0", "model": "1.2.0"} }"trigger_frame_index": nullmeans the search ran and nothing crossed (e.g. a negative decision).POST /predict?compute_trigger=true&verbose=true— also fills the trigger fields insidedetails:{ "is_smoke": true, "probability": 0.98, "trigger_frame_index": 3, "version": {"api": "0.3.0", "model": "1.2.0"}, "details": { "decision": { "aggregation": "max_logit", "threshold": 0.5, "threshold_overridden": false, "packaged_threshold": null, "trigger_tube_id": 7 }, "preprocessing": { "num_frames_input": 30, "num_truncated": 0, "padded_frame_indices": [], "num_tube_candidates": 2, "num_tubes_outside_roi": 0 }, "tubes": [ { "tube_id": 7, "start_frame": 2, "end_frame": 12, "logit": 3.4, "probability": 0.98, "first_crossing_frame": 3, "entries": [ {"frame_idx": 2, "bbox": [0.41, 0.55, 0.04, 0.03], "is_gap": false, "confidence": 0.8} ] } ] } }POST /predict?verbose=true(without the flag) —detailsas today, still no trigger fields.Test plan
api:make lintclean,make test→ 132 passed, 1 skipped