Skip to content

MAINT Extract scenario-history attempt-to-work-unit matching #2768

Description

@romanlutz

Is your feature request related to a problem? Please describe.

MemoryInterface._build_scenario_history_unit_statement() resolves persisted attack attempts to the logical work units used by history counters. It handles planned runs, legacy runs, seed attribution, objective-hash fallback, and deterministic selection between possible matches. This is a substantial query-building responsibility hidden inside the general memory interface.

This is M2 of three scenario-history extraction steps. Not ready yet: depends on #2766. Once that first extraction establishes the internal query boundary, move this matching logic into the same cohesive module. Wait for #2766 to land and confirm that boundary before adding help wanted.

Describe the solution you'd like

Extract only attempt-to-work-unit resolution and its directly related query construction. Keep aggregate arithmetic and aggregate-record conversion in their existing location until the next step.

  • Preserve the current query shape and result-column contract consumed by _build_scenario_history_aggregate_statement().
  • Reuse backend-specific plan-unit/seed expansion and attribution expressions through the internal boundary from MAINT Extract scenario-history page queries from MemoryInterface #2766.
  • Keep exact seed-group matching, objective-hash fallback, technique matching, and deterministic ranking in one understandable unit.
  • Preserve legacy and mixed batches: runs outside the plan-resolution set retain their current identity/counting behavior.
  • Wire the existing aggregate builder to the extracted matching implementation without changing the public memory API.

Acceptance criteria:

  • Planned and planless runs produce the same logical unit identities as before.
  • Exact seed-group matches retain priority over objective-hash fallback; ambiguous matches retain the existing deterministic ordering.
  • Missing or legacy technique attribution preserves current matching behavior.
  • Attempts with no matching planned unit remain excluded from planned-run counters; attempts in legacy runs remain counted as before.
  • Each attempt contributes the same number of rows, without join-induced duplication.
  • Mixed planned/legacy batches and empty plan-resolution sets are covered.
  • SQLite and SQL Server backend hooks remain compatible, and existing memory/service history results remain unchanged.

Describe alternatives you've considered, if relevant

Combining matching and aggregate-counter extraction in one change makes the most intricate SQL harder to review. Moving this logic into Python would change query cost and memory use. Prefer a focused SQL-query extraction into the module from #2766, not a separate service or a new attribution policy.

Additional context

Starting points in pyrit/memory/memory_interface.py: _build_scenario_history_unit_statement, _get_scenario_plan_unit_subqueries, _get_scenario_attempt_unit_expressions, and its caller _build_scenario_history_aggregate_statement. Relevant coverage: tests/unit/memory/memory_interface/test_interface_scenario_history.py and tests/unit/backend/test_scenario_run_service.py.

Follow doc/code/framework.md and the applicable database, Python, and test instructions. No database migration, new public API, or changed retry/success policy is intended. The next step will extract aggregate counting and typed aggregate-record construction using this matching boundary.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    not ready yetThis issue needs more definition or is blocked by a pending change.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions