Repository navigation
feat: Add bounded Scenario result hierarchy projections (#3145) - #3167
Nimit Jain (Nimit3418) wants to merge 29 commits into
Conversation
|
Thank you for the thorough, production-grade review and the concrete edge-case reproductions. I have addressed all 9 requested changes in the latest push:
All linters passed ( |
…nversation clipping (microsoft#3167)
|
Thank you for catching those nuances! All 4 comments from the second review round have been addressed in the latest commit:
All static type checks ( |
|
Note the follow-up responses on a few open threads from above! |
…d reference bounds (microsoft#3167)
|
Thank you for the thorough follow-ups and the heads-up on the open threads! All remaining edge cases have been resolved in the latest push:
All linters ( |
|
A few of the earlier threads remain open (I responded on each) |
Yes sir, I am doing the changes |
…and database shapes (microsoft#3167)
|
Addressed in commit 0e7abda:
|
…ind preview stats to visible nodes (microsoft#3167)
|
All feedback from the latest review round has been resolved in commit
|
…zero-trust conversation stats (microsoft#3167)
|
I have addressed all feedback from your latest review with a focus on strict zero-inference, exact cold/warm cache parity, and eliminating arbitrary query limits. Here is a summary of the architectural updates in commit
|
|
The two remaining open review threads are: Both have concrete examples of the remaining issues in the linked follow-ups. |
…, and preserve exact run statistics (microsoft#3167)
…-identity recount (microsoft#3167)
Roman Lutz (romanlutz)
left a comment
There was a problem hiding this comment.
Summary
Reviewed a1b11089. The earlier examples are fixed, but the bounded-read and parent-context guarantees still have blocking gaps.
Findings
🔴 Full-run hydration is back
Location: pyrit/backend/services/scenario_run_service.py:2546-2549
Removing the recount budget restores exact legacy counts by loading every attempt. A cold one-node request over 2,001 saved legacy attempts hydrates 2,501 deltas across six result-page reads. Please preserve exact shared statistics without requiring full-run attempt-detail hydration. Details in the existing thread.
🔴 Root guards fail at their limits
Location: pyrit/backend/services/scenario_progress_read_model.py:909-914; pyrit/backend/services/scenario_run_service.py:2525-2538
An 11-parent chain emits parent 10 as a root even though it is explicitly marked unverified. At the 2,500-parent budget, newly discovered parents also remain eligible as roots without checking their incoming links. Please preserve unknown parent context through the fallback and budget-exhaustion paths rather than presenting these nodes as confirmed roots. Reproductions in the existing thread.
🔴 SQL Server's parameter limit is exceeded
Location: pyrit/memory/memory_interface.py:7062-7067
All exclusion chunks share one statement, but only 200 exclusion parameters are reserved. The actual Azure SQL query compiles to 2,201 parameters for 1,100 exclusions and 1,100 candidates, above SQL Server's 2,100 limit. Later parent paging with the default node limit can produce 2,501 parameters. Please budget all statement parameters, including the complete exclusion list. The inline comment includes the details.
Verdict
REQUEST CHANGES. Both existing threads remain open; the SQL Server finding is included as an inline comment in this review.
…exclusion SQL params (microsoft#3167) - Add ScenarioAttemptSeedSummary dataclass and memory methods to recount legacy runs with lightweight scalar projections instead of hydrating full ScenarioAttackResultDelta objects with outer joins and JSON parsing. - Remove root promotion fallback for unverified candidates and exclude unverified candidates and their descendants from being emitted as roots during depth-10 and 2,500-parent budget cutoffs. - Dynamically budget bind variables in _execute_get_scenario_parent_deltas_for_child_ids to ensure statement parameters strictly stay within _MAX_BIND_VARS, preventing SQL Server 2,100 parameter overflow when large exclusion lists are present. - Add regression tests verifying depth-10 chain truncation, 2,500-parent boundary guards, lightweight recount without delta hydration, and MSSQL parameter compilation limits with 1,100+ and 2,500+ exclusions.
|
I have pushed commit
|
Roman Lutz (romanlutz)
left a comment
There was a problem hiding this comment.
Summary
Reviewed dfb3ce3. The full-detail hydration and SQL Server parameter-limit findings are addressed and their threads are resolved. Two correctness issues remain.
Findings
🔴 Parent discovery still invents roots
Location: pyrit/memory/memory_interface.py:7175-7178,7232-7243
The Python-only exclusion fallback filters known parents after the SQL row limit. A short filtered page is then treated as complete. In a 1,002-result example, this hides a saved parent and makes the cold hierarchy emit its leaf as a root, while the warm hierarchy emits an actual parent root. Please filter before limiting or explicitly track incomplete parent coverage. Reproduction in the existing thread.
🔴 Retry-event-only attempts disappear from diagnostic totals
Location: pyrit/backend/services/scenario_run_service.py:1771-1774
The lightweight recount ignores saved retry events when total_retries=0. A cold hierarchy reports 0 retrying attacks, while SQL and the warm hierarchy report 1. Please preserve the SQL count or carry a retry-presence flag. The inline comment includes the reproduction and adjacent controls.
Verdict
REQUEST CHANGES. The parent-discovery thread remains open, and the diagnostic finding is included as an inline comment in this review.
…erve retry-event diagnostics (microsoft#3167)
|
I have pushed commit 1. Parent Discovery Keyset Pagination & True Completion
2. Retry-Event Diagnostics Preservation
|
|
One issue is still open: parent discovery can report a child as a root. With 500 leaves and 501 parents, the final query chunk stops at the result limit but returns Could you also merge the latest |
PR Update & Upstream Sync
|
…diagnostic retries
Use native root pages and ordered child continuation without progress-cache hydration. Keep exact shared run statistics independent of clipping, and load selected saved conversations through canonical message-piece paging. Preserve existing unpaged attack APIs and explicit legacy previews. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 60a3baa0-0e4d-428b-8062-5101ad7866dd
Reuse canonical conversation metadata for selected nodes and load all transcript bodies through the generic saved-conversation API. Remove unreleased projection models, preview adapters, and eager tree conversation statistics. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 60a3baa0-0e4d-428b-8062-5101ad7866dd
Use the same active conversation population for hierarchy metadata, paginated lists, and saved transcripts. Exclude internal contexts before counting or paging and preserve existing unpaged behavior. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 60a3baa0-0e4d-428b-8062-5101ad7866dd
Preserve bounded hierarchy reads, shared accounting, and main/pruned conversation scope alongside current main. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 60a3baa0-0e4d-428b-8062-5101ad7866dd
Include the intervening ASSERT cancellation and frontend E2E test updates. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 60a3baa0-0e4d-428b-8062-5101ad7866dd
Roman Lutz (romanlutz)
left a comment
There was a problem hiding this comment.
Reviewed the simplified backend on this revision. Bounded hierarchy reads no longer depend on full progress hydration, exact accounting stays shared, and saved conversation reads consistently expose main/pruned only. The remaining accounting findings are addressed.
Preserve the hierarchy API note in the simplified GUI guide. Give remote-reference tests their own SQLite memory so prior blob-storage tests cannot change their behavior. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 60a3baa0-0e4d-428b-8062-5101ad7866dd
Co-authored-by: Copilot App <[email protected]> Copilot-Session: 60a3baa0-0e4d-428b-8062-5101ad7866dd
Use explicit piece timestamps rather than assuming clock precision orders consecutive constructors. Preserve the existing message-piece paging and UUID tie-break contract. Co-authored-by: Copilot App <[email protected]> Copilot-Session: 60a3baa0-0e4d-428b-8062-5101ad7866dd
Co-authored-by: Copilot App <[email protected]> Copilot-Session: 60a3baa0-0e4d-428b-8062-5101ad7866dd
|
Thank you so much for the detailed review, guidance, and help with the final integration merges Roman Lutz (@romanlutz)! Really excited to see this land in PyRIT. |
Description
Implements #3145 as a backend foundation for browsing a saved scenario's attacks in the GUI. The frontend hierarchy browser remains a separate follow-up.
child_attack_result_idsedge store. Bound detail hydration and output, preserve parent-relativechild_indexseparately from producerattempt_index, and report missing, cross-run, and cyclic references.ConversationSummaryand generic saved-conversation API instead of maintaining hierarchy-only transcript models. Trees defer conversation reads, selected nodes expose bounded main/pruned metadata, and transcript bodies use message-piece pagination. Adversarial and preparation contexts stay internal.Closes #3145.
Tests and Documentation
Added SQLite/HTTP parity and pagination coverage, hierarchy model tests, and SQL Server query-compilation tests. Cases cover clipped and unclipped accounting, legacy identities, linked child errors, native root paging, child continuation, malformed references, cycles, and consistent main/pruned conversation membership. Updated the backend API documentation and GUI guide.
Fixed an order-dependent CI test by giving existing remote-media reference tests their own memory fixture. The media access policy is unchanged; the tests also pass with an ambient blob-storage configuration that reproduced the failure.
Local validation:
uv run --no-sync pytest -q -n 4 --tb=short tests\unit\backend\test_scenario_hierarchy_pagination.py tests\unit\backend\test_saved_conversation_read_service.py tests\unit\backend\test_media_persistence.py: 107 passed, 2 skipped.uv run --no-sync ty check pyrit tests\unit: passed.The full unit-test matrix, coverage, frontend, Docker, documentation, and CodeQL workflows are running on the current PR revision. Merge remains gated on the required checks.
JupyText and provider-backed integration/attack runs were not run locally.