You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
scientific(selection): bind candidate K to fitted topic dimension #676
model_selection::statistical_candidate_from_fit(input, candidate_k, model) accepts the candidate label separately from the fitted model. The function computes a finite Schwarz-style score and free-parameter count from model, but it never verifies that candidate_k equals the fitted topic dimension.
That means a dimensionally valid 2-topic ReferenceTopicModel can be scored and emitted as ModelCandidate::statistical(3, ...). select_candidate_k(...) then treats the mislabeled K as statistical authority, so the model-selection decision can attribute one fit's diagnostic to a different topic count.
The ordinary select_fitted_candidate_k(...) loop currently passes matching values, but the public scoring API itself is not fail closed and can manufacture a scientifically false K/diagnostic association.
Required RED
At the public statistical_candidate_from_fit boundary:
a valid model scored with its actual topic count remains accepted;
the same model passed with a different candidate_k returns ModelSelectionError::InvalidDiagnostic before creating ModelCandidate;
the repair does not alter likelihood arithmetic, free-parameter counting, candidate Pareto logic, fitted estimator arithmetic, or LLM refusal rules.
A small synthetic unit/integration fixture is sufficient because this is an API identity invariant, not scientific acceptance evidence.
Minimal causal direction
Derive the fitted topic count from the model's document-topic coordinate width, validate that it is representable as u32, and require exact equality with candidate_k before calculating or emitting the candidate score. Keep existing dimensional validation in free_parameter_count as defense in depth.
Boundary
This issue closes only K/fit label integrity. It does not solve the separate detached input/model substitution path in statistical_candidate_from_fit, Evidence provenance (#527/#658/#671/#675), fitted-topic semantic identity (#663), or release projection (#664).
Ordinary-forward implementation on canonical #639 lane:
RED a60bd819d5b4cbadf2e8a2723451eb102467a8e0: public integration contract constructs a valid two-topic model, proves K=2 remains accepted, and requires the same fit mislabeled as K=3 to fail closed. The superseded RED head did not produce a hosted failing result; Security/Semgrep/CodeQL/Documentation were cancelled and Rust Foundation remained queued when the repair advanced.
minimal repair 30ba85058a374f25d8cff1d41d477832ba38f0dd: statistical_candidate_from_fit preserves candidate_k < 2 -> NonPositiveCandidateK, runs existing model-dimension validation, derives the fitted topic count from topic_term_probabilities.len() with checked u32 conversion, and rejects a mismatched label as InvalidDiagnostic before likelihood/score emission. RED→repair compare is one production file, +14/-3; estimator arithmetic, likelihood formula, free-parameter formula, Pareto gate and LLM refusal are unchanged.
This closes only K/fit-label integrity. The public scorer still accepts detached ReferenceTopicInput + ReferenceTopicModel; a dimension-compatible A-input/B-model substitution remains a separate owner-binding gap and should be repaired through ReferenceTopicFit, not by inventing a digest.
Activity
test(selection): reject mismatched fitted candidate K (#676)
fix(selection): bind candidate K to fitted dimension (#676)
seonghobae commentedon Sep 22, 2026
Ordinary-forward implementation on canonical #639 lane:
a60bd819d5b4cbadf2e8a2723451eb102467a8e0: public integration contract constructs a valid two-topic model, provesK=2remains accepted, and requires the same fit mislabeled asK=3to fail closed. The superseded RED head did not produce a hosted failing result; Security/Semgrep/CodeQL/Documentation were cancelled and Rust Foundation remained queued when the repair advanced.30ba85058a374f25d8cff1d41d477832ba38f0dd:statistical_candidate_from_fitpreservescandidate_k < 2 -> NonPositiveCandidateK, runs existing model-dimension validation, derives the fitted topic count fromtopic_term_probabilities.len()with checkedu32conversion, and rejects a mismatched label asInvalidDiagnosticbefore likelihood/score emission. RED→repair compare is one production file, +14/-3; estimator arithmetic, likelihood formula, free-parameter formula, Pareto gate and LLM refusal are unchanged.This closes only K/fit-label integrity. The public scorer still accepts detached
ReferenceTopicInput + ReferenceTopicModel; a dimension-compatible A-input/B-model substitution remains a separate owner-binding gap and should be repaired throughReferenceTopicFit, not by inventing a digest.docs(selection): record fit authority and Schwarz score repairs (#676-#…