|
22 | 22 | LedgerReason, |
23 | 23 | LedgerRecordType, |
24 | 24 | analyzer_status_event, |
| 25 | + analyzer_status_for_events, |
25 | 26 | finalize_ledger, |
26 | 27 | guard_analyzer_node, |
27 | 28 | inspection_work_id, |
@@ -125,6 +126,55 @@ def test_completed_work_is_covered_and_resolves_emitted_finding_ids() -> None: |
125 | 126 | assert effective_ids == [finding.finding_id] |
126 | 127 |
|
127 | 128 |
|
| 129 | +def test_out_of_scope_boundaries_do_not_count_as_analyzer_failures() -> None: |
| 130 | + """Non-fatal scope boundaries are not planned work for an analyzer.""" |
| 131 | + analyzer_id = "static_patterns_prompt_injection" |
| 132 | + inspected = ledger_event( |
| 133 | + outcome=LedgerOutcome.COMPLETED, |
| 134 | + phase="static", |
| 135 | + analyzer_id=analyzer_id, |
| 136 | + path="scripts/run.py", |
| 137 | + ) |
| 138 | + excluded = ledger_event( |
| 139 | + outcome=LedgerOutcome.OUT_OF_SCOPE, |
| 140 | + record_type=LedgerRecordType.SCOPE_BOUNDARY, |
| 141 | + phase="static", |
| 142 | + analyzer_id=analyzer_id, |
| 143 | + path="assets/font.ttf", |
| 144 | + reason=LedgerReason.BINARY_CONTENT, |
| 145 | + ) |
| 146 | + |
| 147 | + completeness, _ = finalize_ledger( |
| 148 | + { |
| 149 | + "components": ["scripts/run.py", "assets/font.ttf"], |
| 150 | + "findings": [], |
| 151 | + "inspection_ledger": [inspected, excluded], |
| 152 | + "analyzer_status_events": [ |
| 153 | + analyzer_status_for_events(analyzer_id, [inspected, excluded]) |
| 154 | + ], |
| 155 | + "artifact_inventory": [ |
| 156 | + {"path": "scripts/run.py", "disposition": "complete"}, |
| 157 | + { |
| 158 | + "path": "assets/font.ttf", |
| 159 | + "disposition": "out_of_scope", |
| 160 | + "content_kind": "binary", |
| 161 | + }, |
| 162 | + ], |
| 163 | + } |
| 164 | + ) |
| 165 | + |
| 166 | + status = next( |
| 167 | + row for row in completeness["analyzer_statuses"] if row["analyzer_id"] == analyzer_id |
| 168 | + ) |
| 169 | + assert status["status"] == "completed" |
| 170 | + assert status["planned_work"] == 1 |
| 171 | + assert status["completed"] == 1 |
| 172 | + assert status["failed"] == 0 |
| 173 | + assert completeness["scope_exclusions"][0]["path"] == "assets/font.ttf" |
| 174 | + assert completeness["status"] == "complete" |
| 175 | + assert completeness["coverage_percent"] == 100.0 |
| 176 | + |
| 177 | + |
128 | 178 | def test_missing_terminal_row_becomes_fatal_unaccounted_work() -> None: |
129 | 179 | work_id = inspection_work_id("behavioral_ast", "broken.py", None, None) |
130 | 180 |
|
|
0 commit comments