fix(report): flag a partial LLM failure as degraded, not only a total one - #362
Conversation
rng1995
left a comment
There was a problem hiding this comment.
The report-level predicate now handles mixed analyzer outcomes, but the core partial-batch path is still recorded as a success upstream, so a multi-batch analyzer can drop work and still produce SAFE. The new predicate also conflates overall coverage with whether the meta-analyzer/provider actually ran. Please address the inline findings so the degraded verdict and metadata are accurate end to end.
…p meta-analysis fields inheriting other analyzers' failures Two gaps from review on NVIDIA#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 <amirfathi.me@gmail.com>
|
Pushed a follow-up commit for both findings. P1 (line 587): P2 (line 617/626): I did not add a separate coverage field beyond the existing Verified: ran the new/changed tests against the pre-fix code first to confirm they fail (3 of 4 red, the meta_analyzer-failure case already passed under the old formula since that one case wasn't actually broken), then confirmed green after the fix. |
|
No rush, just flagging this is still open. Pushed a fix for both review findings on 08-12 (full suite green), but I can't request a re-review myself and the CI run for that commit is still waiting on the approval gate. |
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
Re-review: still requesting changes. Partial-batch failures now correctly reach the degraded verdict, but the metadata contract remains wrong: all([]) marks meta_analysis_applied true when the no-findings path made no meta-analyzer call at all. Require an actual successful meta-analyzer record for that field and add the no-record regression described inline; provider availability should remain separate.
|
You're right, that was a real gap. Changed Added Verified in a clean |
… 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 <amirfathi.me@gmail.com>
…p meta-analysis fields inheriting other analyzers' failures Two gaps from review on NVIDIA#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 <amirfathi.me@gmail.com>
…_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 <amirfathi.me@gmail.com>
e2fa069 to
8da67ed
Compare
|
Rebased onto main, no conflicts in the source (only a test file collided with a new upstream test added at the same location, both kept). Full suite, ruff lint and format-check all clean at the new head. |
rng1995
left a comment
There was a problem hiding this comment.
[SkillSpector Review]
Re-review approved. The remaining metadata blocker is resolved: meta_analysis_applied now requires at least one successful meta_analyzer record, while provider availability remains independent when no meta-analysis call was needed. The no-record regression covers the prior all([]) gap, and all required checks pass.
…aded Signed-off-by: Amir Fathi <amirfathi.me@gmail.com>
9aa31e6 to
19076ed
Compare
|
Thanks for catching both review gaps, the empty-list |
What
report()derivesdegradedfrom_llm_runtime_status(), which only set it when every attempted LLM call failed (succeeded == 0). A rate-limited provider that drops one batch (e.g. a 429 onsemantic_security_discovery) still hassucceeded > 0, so the existing fail-closed floor (CAUTIONinstead ofSAFEon a degraded scan) never triggered. The reported scenario is exactly this:llm_calls_attempted=4, llm_calls_succeeded=3,risk_assessmentstill SAFE, and the dropped batch happened to be the one analyzer that would have caught the malicious skill in the report.This widens the condition to
succeeded < attempted, so any dropped or throttled batch marks the scan degraded, not just a total failure. The two degraded-scan messages (_llm_degradation_notice,meta["llm_error"]) are updated to say how many of the calls failed instead of assuming all of them did, since that is no longer always true.Test
Added
test_partial_llm_failure_also_floors_recommendation_at_caution, matching the reported3/4scenario directly againstreport(). Renamed the test that pinned the old behavior (test_report_not_degraded_when_some_calls_succeeded->test_report_degraded_when_some_calls_fail) to assert the corrected one. Fulltests/nodes/test_report.pygreen (63 passed);make lintandmake format-checkclean.Scope
This 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, which this PR does not touch or conflict with (it does not modify
_llm_runtime_status).Refs #303