Skip to content

[BREAKING] FEAT: Restructure Psychosocial scenario for per-subharm scoring#1943

Open
varunj-msft wants to merge 2 commits into
microsoft:mainfrom
varunj-msft:varunj-msft/8380-Standardizing-Scenarios-Psychosocial-bugfix
Open

[BREAKING] FEAT: Restructure Psychosocial scenario for per-subharm scoring#1943
varunj-msft wants to merge 2 commits into
microsoft:mainfrom
varunj-msft:varunj-msft/8380-Standardizing-Scenarios-Psychosocial-bugfix

Conversation

@varunj-msft

@varunj-msft varunj-msft commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Description

Restructures the Psychosocial scenario so strategies are techniques and subharms are datasets. Started as the --max-dataset-size fast-path bugfix and grew into the full standardization Rich sketched in review.

  1. Strategies are techniques now. The strategy enum is prompt_sending, role_play, crescendo instead of the old subharm-as-strategy anti-pattern. Subharm selection moves off --strategies and onto --dataset-names.

  2. Seed file split per subharm. psychosocial.prompt becomes airt_imminent_crisis.prompt + airt_licensed_therapist.prompt, each carrying its own scorer rubric and crescendo escalation prompt. This removes runtime harm-filtering entirely — there's no longer a cap-vs-filter ordering to get wrong, which is what made --max-dataset-size 1 fail before.

  3. Per-subharm scorers. One FloatScaleThresholdScorer is built per subharm and routed to both the AtomicAttack and the technique's AttackScoringConfig, so running all no longer scores attacks with the wrong rubric.

  4. Per-subharm baselines. Via a generalized base-class mechanism. Baseline identity now lives on the model: AtomicAttack gains an is_baseline flag, and the central baseline rescue in Scenario.initialize_async checks any(aa.is_baseline for aa in self._atomic_attacks) instead of matching the literal name "baseline". MatrixAtomicAttackBuilder gains a BaselineSpec dataclass and a plural _build_baseline_atomic_attacks helper. Psychosocial uses this to emit one baseline per subharm (baseline_imminent_crisis / baseline_licensed_therapist), each carrying that subharm's scorer and display group, so the two no longer collide on a shared "baseline" key. Foundry's red_team_agent.py bare composite (no attack, no converters) is flagged is_baseline so it is likewise recognized and not double-prepended.

  5. initialize_async validates dataset names. A user-supplied dataset_config is allowed only if its dataset names are a subset of the subharms, so --max-dataset-size N still works while custom names are rejected with a clear error.

Crescendo is kept out of the default aggregate (opt-in via --strategies all / --strategies crescendo) since it's the heaviest technique — default runs are single-turn. BASELINE_ATTACK_POLICY is back to Enabled, and VERSION is bumped 2→3 because the default behavior changed; stored v2 results raise cleanly on --resume rather than silently mixing semantics.

One deliberate divergence from the review sketch, flagged inline: TARGET_REQUIREMENTS is left at the base default rather than EDITABLE_HISTORY. With Crescendo opt-in, the default run is single-turn, and requiring editable history at the scenario level would reject OpenAIChatTarget before the strategy resolves. Crescendo enforces that requirement itself when it runs. Easy to flip back if preferred.

Tests and Documentation

Reworked tests/unit/scenario/airt/test_psychosocial.py around the new shape — 27 tests across 6 classes:

  • TestPsychosocialStrategyEnum / TestPsychosocialTechniques — enum members, default tags, Crescendo excluded from default
  • TestSubharmConfigs — both subharms wired with the right dataset, scorer prompt, and crescendo path
  • TestPsychosocialInitialization — VERSION == 3, baseline policy
  • TestPsychosocialDatasetConfigValidation — max_dataset_size=1 on a valid subharm doesn't raise; custom / unknown names do
  • TestPsychosocialCrossProduct — (technique × subharm) atomic attacks with correct names, per-subharm scorer routing, and per-subharm baselines

This PR also generalizes baseline handling in shared infrastructure (pyrit/scenario/core/atomic_attack.py, matrix_atomic_attack_builder.py, scenario.py) and updates Foundry (pyrit/scenario/scenarios/foundry/red_team_agent.py), with a regression test tests/unit/scenario/foundry/test_red_team_agent.py::test_bare_composite_baseline_not_double_prepended.

Validation:

  • pytest tests/unit/scenario/airt/test_psychosocial.py → 27 passed
  • pytest tests/unit/scenario/ (full scenario suite) → all passing, no regressions
  • ruff check + ruff format --check + ty → all clean

Comment thread pyrit/scenario/scenarios/airt/psychosocial.py Outdated
Comment thread pyrit/scenario/scenarios/airt/psychosocial.py Outdated
Comment thread pyrit/scenario/scenarios/airt/psychosocial.py Outdated
Comment thread pyrit/scenario/scenarios/airt/psychosocial.py Outdated
@varunj-msft varunj-msft force-pushed the varunj-msft/8380-Standardizing-Scenarios-Psychosocial-bugfix branch from 6106e65 to 5dcb74a Compare June 17, 2026 01:30
@varunj-msft varunj-msft changed the title [BREAKING] FIX: Psychosocial harm-category filtering and baseline default [BREAKING] FEAT: Restructure Psychosocial scenario for per-subharm scoring Jun 17, 2026
@varunj-msft

Copy link
Copy Markdown
Contributor Author

Pushed the restructure. Only open question is TARGET_REQUIREMENTS (in the refactor thread). Also retitling since this isn't a bugfix anymore

@rlundeen2 rlundeen2 self-assigned this Jun 22, 2026
@rlundeen2

Copy link
Copy Markdown
Contributor

Maybe we should hold off until the DataConfiguration refactor is in

Comment thread pyrit/scenario/scenarios/airt/psychosocial.py Outdated
Re-implement the Psychosocial scenario following rlundeen2's review:

- Split the single combined dataset into two per-subharm datasets
  (airt_imminent_crisis, airt_licensed_therapist), each with its own
  scoring rubric and Crescendo escalation prompt.
- Build atomic attacks as the (technique x subharm) cross product, so each
  attack carries the scorer matching its seed's subharm. This fixes the bug
  where running all subharms scored every attack with a single fallback rubric.
- Move subharm selection to --dataset-names; strategies are now technique-only
  (prompt_sending / role_play in the default aggregate, crescendo opt-in).
- Keep the baseline enabled by default, emitting one baseline per subharm with
  its matching scorer; name the first "baseline" so the base scenario does not
  additionally prepend a generic single-scorer baseline.
- Raise a clear error when no seeds are loaded for any selected subharm instead
  of surfacing the base class's cryptic empty-seed_groups failure.

VERSION bumped to 3.
@varunj-msft varunj-msft force-pushed the varunj-msft/8380-Standardizing-Scenarios-Psychosocial-bugfix branch from 5dcb74a to f9df8af Compare July 7, 2026 01:28
… scoring

Add a plural _build_baseline_atomic_attacks helper + BaselineSpec and an
is_baseline flag on AtomicAttack. Switch the central baseline rescue to check
is_baseline instead of the atomic_attack_name == "baseline" literal, so an
override can emit its own baselines under any name and the base does not
double-prepend.

Psychosocial now emits one baseline per subharm through the shared helper
(each with that subharm's scorer and display group) instead of hand-rolling
PromptSendingAttack/AtomicAttack. Foundry's bare composite (no attack, no
converters) is flagged is_baseline so it is likewise recognized and not
double-prepended.
@varunj-msft

Copy link
Copy Markdown
Contributor Author

Unblocked now - the DataConfiguration refactor (#2071/#2100) is merged and I've rebased on top, so this is ready for another pass!

@rlundeen2

Copy link
Copy Markdown
Contributor

The scenario doesn't use the new patterns. It predates the refactor.

ScenarioContext.seed_groups_by_dataset does do what I asked for, but the issue is solved upstream.

  1. The subharms diverged (the strategies are the subharms)
  2. The techniques are probably poor fits. E.g. Roleplay Movie script is probably not the right strategy to test for licenced therapist; and success is measuring the wrong thing.
  3. There are some big conflict hunks if you try to merge main (because it's using the old patterns).

I might build on top of main, and get rid of this branch. Keep some ideas here (per-subharm scorer + crescendo path, per-subharm baseline naming) but express them via _build_atomic_attacks_async(context), seed_groups_by_dataset, central baseline, and subharm-aware technique selection (dropping role_play for licensed_therapist).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants