Files
udyamlinc-api/src/main/java/com/lincfusion/udyamlinc/ml/MlProperties.java
T
LincPayandClaude Opus 5 6b4aec468d feat(risk): bind the scoring engine to the ML service, with honest attribution
Adds MlClient and the two model-backed strategies behind the existing
ScoringStrategy / ForecastStrategy seams, so switching engines stays a config
value rather than a code change.

MlClient never throws. Every call returns Optional.empty() on any failure —
timeout, connection refused, malformed body — and ModelScoringStrategy falls
back to the rule engine for that enterprise. A nightly run must complete, and
a demo must survive the Python process dying mid-presentation.

The important part is what the fallback records. A run configured MODEL used
to stamp every score MODEL even when the ML service was down and rules had
actually produced the number, which made the provenance column a lie exactly
when it mattered. ScoreOutcome now carries an `engine` field and the fallback
returns .attributedTo("RULE_FALLBACK"). Verified by killing the service
mid-run: run 285 MODEL, run 286 RULE_FALLBACK, 260 of 263 scores differ.

ModelMetric and its read-only controller expose the measured backtest at
GET /admin/model/metrics. syntheticLabelShare is stored on the same row as
every metric so accuracy cannot be quoted without the caveat travelling with
it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 13:44:07 +05:30

33 lines
1.0 KiB
Java

package com.lincfusion.udyamlinc.ml;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Where the inference service is, and how long we are willing to wait for it.
*
* <p>Timeouts are short on purpose. A scoring run over the whole book must finish
* inside its window, and an inference service that has become slow is
* operationally the same as one that is down — both mean "score this enterprise
* on rules and move on".
*/
@Component
@ConfigurationProperties(prefix = "udyam.ml")
@Getter
@Setter
public class MlProperties {
/** Off by default: a checkout with no Python running must still boot and score. */
private boolean enabled = false;
private String baseUrl = "http://127.0.0.1:8000";
/** Per-enterprise call. */
private int timeoutMs = 2000;
/** Batch call over the book — larger, because it is one call for 263 rows. */
private int batchTimeoutMs = 30000;
}