Repository navigation
feat(llm): configurable analyzer fan-out concurrency via SKILLSPECTOR_MAX_LLM_CONCURRENCY (part of #303) - #305
Conversation
`arun_batches` bursts up to a hardcoded `max_concurrency=10`. On a rate-limited provider (free tiers with a low RPM) that burst guarantees 429s, and 429'd batches are dropped from the result — silently losing analyzer coverage, including the security-critical `semantic_security_discovery` batch, while the report still renders a full risk_assessment. Add `SKILLSPECTOR_MAX_LLM_CONCURRENCY` so users can serialize the fan-out (set it to 1) and stay under the provider's rate limit. The default stays 10; an explicit `max_concurrency=` argument still wins. Invalid values fall back to the default, values < 1 clamp to 1. Part of NVIDIA#303 (the retry/backoff and partial-pass surfacing are separate). Adds unit tests for the env resolution. Signed-off-by: Mark2Mac <[email protected]>
rng1995
left a comment
There was a problem hiding this comment.
[Automated SkillSpector Review]
Approved. The default remains 10, explicit arguments retain precedence, environment parsing handles invalid and blank values safely, and values below one are clamped. The focused resolver tests cover the new configuration behavior; no schema or security regression found.
|
Gentle ping. This one touches the async core, so if you would rather solve #303 your own way I am happy to close it — the part I care about is that a rate-limited provider currently loses analyzer coverage silently. For context on why the knob matters in practice: on the Gemini AI Studio free tier the per-model allowance is 20 requests/day and 5 RPM, so the hardcoded Also filed #318 (SC4 and version ranges) from the same audit, in case it is useful signal on the supply-chain analyzer. |
|
Can you resolve conflicts? @Mark2Mac |
Signed-off-by: keshprad <[email protected]>
d58aeb0 to
85a4e7d
Compare
… one _llm_runtime_status() only set degraded when every LLM call failed (succeeded == 0). A rate-limited provider that drops a single batch (e.g. semantic_security_discovery hits a 429) still has succeeded > 0, so the scan reported a normal risk_assessment even though the security-critical analyzer never ran. Widen the condition to succeeded < attempted, so any dropped batch degrades the scan and the existing fail-closed floor (CAUTION instead of SAFE) applies to a partial pass too. Updated the two degraded-scan messages to say how many of the calls failed instead of assuming all of them did. Covers request 3 of NVIDIA#303 (surface incompleteness in the verdict). Request 1 (configurable concurrency) shipped in NVIDIA#305; request 2 (retry with backoff) is left to the already-open NVIDIA#29. Refs NVIDIA#303 Signed-off-by: Amir Fathi <[email protected]>
… one (#362) * fix(report): flag a partial LLM failure as degraded, not only a total one _llm_runtime_status() only set degraded when every LLM call failed (succeeded == 0). A rate-limited provider that drops a single batch (e.g. semantic_security_discovery hits a 429) still has succeeded > 0, so the scan reported a normal risk_assessment even though the security-critical analyzer never ran. Widen the condition to succeeded < attempted, so any dropped batch degrades the scan and the existing fail-closed floor (CAUTION instead of SAFE) applies to a partial pass too. Updated the two degraded-scan messages to say how many of the calls failed instead of assuming all of them did. Covers request 3 of #303 (surface incompleteness in the verdict). Request 1 (configurable concurrency) shipped in #305; request 2 (retry with backoff) is left to the already-open #29. Refs #303 Signed-off-by: Amir Fathi <[email protected]> * fix(report): mark a batch record failed on any dropped batch, and stop meta-analysis fields inheriting other analyzers' failures Two gaps from review on #362: 1. llm_call_log records were built with ok=bool(outcome.successful) or not outcome.failures, so an analyzer with one succeeded batch and one dropped/429'd batch still recorded ok=True. In that exact case succeeded == attempted at the report layer and the scan stayed SAFE, defeating the partial-coverage fix. Now the record is ok=not outcome.failures: any dropped batch marks the whole record failed. Applied identically in the three semantic analyzers and meta_analyzer, the four call sites that build this record. 2. meta_analysis_applied and the llm_available field were derived from the aggregate `degraded` flag, which pools every LLM-backed node together. That let a different analyzer's dropped batch force meta_analysis_applied=False, filtering_mode="heuristic" and llm_available=False even when meta_analyzer's own call fully succeeded, misstating two independent contracts (meta-analysis ran vs. some coverage was lost) as one boolean. Both fields now derive from is_llm_available() plus meta_analyzer's own llm_call_log record only; the coverage loss from other analyzers still surfaces through llm_degraded / llm_calls_attempted / llm_calls_succeeded, unchanged. Verified: test_partial_batch_failure_records_llm_failure (renamed from ..._records_llm_success, now pins ok=False) and three new report-level tests, run red against the pre-fix code (3 of 4 failed) and green after. tests/nodes/test_report.py: 66 passed. Full suite in Docker (python:3.12-slim): 1947 passed, 13 skipped, 4 xfailed, 0 failed. ruff lint and format-check both pass. Signed-off-by: Amir Fathi <[email protected]> * fix(report): require an actual meta_analyzer record for meta_analysis_applied all([]) is True on an empty list, so an empty meta_analyzer_records left meta_analysis_applied True even when meta_analyzer made no call at all (the no-findings path, where it short-circuits to not_applicable). That still violated the "did meta-analysis actually run" contract from the prior review. meta_analysis_applied now requires at least one meta_analyzer record and all of them ok. llm_available is unchanged: provider availability is a separate contract from whether meta_analyzer had anything to do, and it stays vacuously true when meta_analyzer never ran. Adds a regression covering the no-findings/no-record case, asserting meta_analysis_applied is False while llm_available stays True. Signed-off-by: Amir Fathi <[email protected]> --------- Signed-off-by: Amir Fathi <[email protected]>
What
arun_batchesfans out up to a hardcodedmax_concurrency=10. On a rate-limited provider (free tiers with a low RPM) that burst guarantees 429s, and — per the method's own contract — 429'd batches are logged and omitted from the result. The scan silently loses analyzer coverage, including the security-criticalsemantic_security_discoverybatch, while still emitting a fullrisk_assessment. A genuinely malicious skill can then read as clean.This adds an env knob so users on such tiers can serialize the fan-out and stay under the limit:
max_concurrency=argument still wins.< 1clamp to 1.Test
TestResolveMaxConcurrency: unset→default, valid→value, blank→default, invalid→default,0→1. Fulltest_llm_analyzer_base.pysuite green (116 passed); ruff clean.Scope
This is the first of the three asks in #303 (configurable concurrency). The retry/backoff on 429 and surfacing a partial LLM pass in the verdict are larger changes left for separate PRs / discussion.
Refs #303