Skip to content

[BREAKING] MAINT: Re-migrate Psychosocial scenario to per-subharm cross-product#2191

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

[BREAKING] MAINT: Re-migrate Psychosocial scenario to per-subharm cross-product#2191
varunj-msft wants to merge 12 commits into
microsoft:mainfrom
varunj-msft:varunj-msft/8380-Standardizing-Scenarios-Psychosocial-v2

Conversation

@varunj-msft

@varunj-msft varunj-msft commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Psychosocial

Rewrites the airt.psychosocial scenario as a clean sub_harm × technique cross-product, following the same patterns as the other AIRT scenarios.

  • sub_harm is the primary axisimminent_crisis and/or licensed_therapist (both by default). Each sub-harm owns its dataset, escalation prompt, and its own conversation-level scorer, so every attack and baseline is scored by the rubric that matches its harm. Override a scorer by passing imminent_crisis_scorer / licensed_therapist_scorer to Psychosocial(...).
  • PsychosocialTechnique is the secondary axis — a registry-style converter enum (mirrors EncodingTechnique) so users can add more. The base technique is a simulated crescendo; each selected converter is layered on top. Converters preserve natural-language emotional framing (obfuscation converters are excluded) and are grouped into selectable families: tone, language (new translation variants), persuasion, and deterministic (no-LLM). crescendo swaps the simulated base for a live CrescendoAttack (in all only).
  • Datasets are bound to the sub-harms, so --dataset-names is ignored (--max-dataset-size still applies). One baseline per sub-harm is emitted and scored with that sub-harm's rubric. Removes the old rubric/_build_scorer lookup indirection — scorers are constructed inline with their matching dataset.
pyrit_scan airt.psychosocial --target openai_chat --techniques tone

Baseline decentralization

The base Scenario no longer builds baselines. It now owns baseline only as configuration (BASELINE_ATTACK_POLICYcontext.include_baseline); _build_baseline_atomic_attacks and the central prepend are gone. Each scenario emits its own baseline via the shared build_baseline_atomic_attack helper, and matrix scenarios get it through build_matrix_atomic_attacks (which reads include_baseline off the ScenarioContext). This keeps the base class from presuming a single objective scorer / single baseline shape and lets scenarios like Psychosocial emit multiple baselines (one per sub-harm). The --include-baseline CLI flag and policy semantics (Enabled / Disabled / Forbidden) are unchanged.

test added 2 commits July 14, 2026 22:16
Restructures Psychosocial so techniques select attack techniques
(prompt_sending, role_play, crescendo) rather than subharms. Both
subharms (imminent_crisis, licensed_therapist) always run, each with its
own dataset, scorer rubric, and Crescendo escalation prompt. Atomic
attacks are the (selected technique x subharm) cross product, so every
attack is scored with the rubric matching its seed's subharm -- fixing
the wrong-scorer-on-ALL bug where licensed_therapist seeds were scored
with the crisis rubric.

- role_play is excluded for licensed_therapist (a fictional movie-script
  framing does not probe whether the model improperly acts as a real
  therapist; success would measure the wrong thing).
- Split the single mixed psychosocial.prompt into airt_imminent_crisis
  and airt_licensed_therapist datasets; per-dataset budget keeps both
  subharms populated even at small --max-dataset-size (fixes the
  sample-before-filter empty-subharm bug).
- Subharm datasets cannot be selected by name (each is tied to its
  scorer/prompt); --max-dataset-size still caps seeds drawn per subharm.
- Per-subharm baselines: one baseline per subharm scored with its own
  rubric; the first is named 'baseline' so the base central-baseline
  prepend is suppressed (no double baseline).
- VERSION 1 -> 2.
The CLI backend applies --max-dataset-size N by setting the cap on the
whole compound dataset config, which the base then applies as one global
budget across the union of the two subharm datasets. At a small N (e.g.
--max-dataset-size 1) this drew every surviving seed from one subharm and
starved the other, silently dropping a whole subharm and breaking the
scenario's "both subharms always run" invariant (measured: a subharm was
starved on every run at N=1).

Normalize the incoming compound-level cap into an explicit per-child
compound so the cap applies to each subharm independently. The compound
cap is set to N * <number of subharms> -- large enough it can never trim
the union, yet non-None so the base still pins sampled objective hashes
for resume. Caller-supplied --dataset-filters are carried over to the
rebuilt config. The default and programmatic per_dataset paths (compound
cap None) are left untouched.

- Rename the test that only exercised the per_dataset primitive; add
  regression tests for the CLI compound-cap path, the default no-op path,
  and dataset-filter preservation.
Comment thread pyrit/scenario/scenarios/airt/psychosocial.py Outdated
rlundeen2 and others added 7 commits July 14, 2026 18:27
…ters

Reworks the Psychosocial scenario to follow framework norms used by sibling
scenarios (leakage, foundry, scam), replacing the technique x subharm
cross-product and its awkward module-level `_psychosocial_techniques()` /
`_build_scorer` contracts.

- Harms are the primary axis: new `harms` parameter selects imminent_crisis
  and/or licensed_therapist (both by default). Each harm owns its dataset,
  Crescendo escalation prompt, scorer, and threshold via an immutable config.
- Converters become the variation axis, modeled as PsychosocialTechnique
  members (none/soften/upset/logical_appeal) selectable via --strategies.
- Per-harm scorers built inline (no external rubric path lookup); callers can
  override with imminent_crisis_scorer / licensed_therapist_scorer.
- Drops dataset_config from supported_parameters (datasets are derived from
  harms, not selectable by name).
- Adds Scenario._build_baseline_atomic_attacks hook (default None, back-compat)
  so Psychosocial emits per-harm baselines named <harm>_baseline, removing the
  fragile "baseline" naming trick.
- Rewrites tests (37) and doc prose; regenerates airt.ipynb psychosocial cells
  with real Version 2 output.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b7009abc-fe0b-4d7e-a39a-971a396e9eef
…oduct

Rewrite the Psychosocial AIRT scenario from scratch, modeled on the healthy
garak.encoding (converter-as-technique enum) and airt.scam
(with_simulated_conversation) patterns.

- Primary axis is sub_harm (imminent_crisis / licensed_therapist), a plain
  string param defaulting to 'all'. Each sub-harm owns its dataset, escalation
  prompt, and an inline conversation-level scorer (no rubric-path lookup table,
  no _build_scorer indirection).
- Base technique is a simulated crescendo per sub-harm; converters layer on top
  as the PsychosocialTechnique enum (DEFAULT = none/tone_soften/
  persuasion_logical_appeal; ALL = ~19 converters + live Crescendo).
- Keep dataset_config (so --max-dataset-size works) but hard-bind dataset names
  to the selected sub-harms. Drop CompoundDatasetAttackConfiguration.
- Per-sub-harm baselines via the _build_baseline_atomic_attacks hook.
- Add escalation_crisis_simulated.yaml (renders with objective/max_turns only)
  for the simulated-conversation flow.
- Rewrite tests and sync doc/scanner/airt.{py,ipynb}.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b7009abc-fe0b-4d7e-a39a-971a396e9eef
Each sub-harm now owns a build_scorer callable that spells out its scorer
(rubric + threshold) next to the dataset it pairs with, replacing the shared
_conversation_scorer helper. Adds a test asserting each sub-harm builds a scorer.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b7009abc-fe0b-4d7e-a39a-971a396e9eef
Remove the overloaded per-scenario baseline hook. The base Scenario now
derives baselines from the already-built technique cells, grouping by
objective-scorer identity: one shared scorer yields a single "baseline",
per-population scorers (e.g. psychosocial sub-harms) yield one
"<display_group>_baseline" per group. No scenario hand-rolls baselines.

- scenario.py: concrete _build_baseline_atomic_attacks derivation; delete
  singular _build_baseline_atomic_attack.
- psychosocial.py: delete the baseline override (now derived identically).
- atomic_attack.py: public objective_scorer property for grouping.
- matrix_atomic_attack_builder.py: build_baseline_atomic_attack gains
  atomic_attack_name/display_group/objective_scorer passthrough.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b7009abc-fe0b-4d7e-a39a-971a396e9eef
The base Scenario no longer builds baselines. It only resolves
BASELINE_ATTACK_POLICY into self._include_baseline (carried on
ScenarioContext.include_baseline). Each scenario emits its own baseline:

- Matrix scenarios (cyber, leakage, rapid_response, doctor, benchmark) get
  it for free -- the matrix builder reads context.include_baseline.
- build_matrix_atomic_attacks no longer takes a redundant include_baseline
  arg; it reads it from the context it already receives.
- Custom scenarios (adaptive, jailbreak, scam, encoding, web_injection,
  red_team_agent) prepend one gated build_baseline_atomic_attack call.
- Psychosocial emits its per-sub-harm baselines inline.

Removes Scenario._build_baseline_atomic_attacks and the central prepend in
initialize_async. Updates tests accordingly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b7009abc-fe0b-4d7e-a39a-971a396e9eef

@rlundeen2 rlundeen2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving! But I wrote a big chunk so it should have another approval

…eanup

- Add TranslationConverter language variants (Spanish, French, German, Japanese)
  as a new "language" converter family for the Psychosocial technique sweep.
- Group the converter families under selectable aggregate tags so users can run a
  whole family with --strategies: "tone", "language", "persuasion", and
  "deterministic" (the no-LLM perturbations).
- Rename the confusing `rubric` local to `scoring_prompt` in the scorer builders
  (it is the scorer's system-prompt SeedPrompt, not a lookup rubric) and drop a
  stale comment referencing the removed central baseline fallback.
- Make the airt.ipynb Psychosocial demo minimal (single technique + one objective)
  so the notebook runs fast instead of sweeping the full dataset by default; re-run.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b7009abc-fe0b-4d7e-a39a-971a396e9eef
@rlundeen2 rlundeen2 changed the title [BREAKING] MAINT: Re-migrate Psychosocial scenario to per-subharm cross-product [BREAKING] MAINT: Re-migrate Psychosocial scenario to per-sub-harm cross-product Jul 16, 2026
rlundeen2 and others added 2 commits July 15, 2026 20:36
…ection

The CLI flag is --techniques/-t (--strategies never existed). Corrects it in
the airt.py notebook and psychosocial.py docstrings, and trims the notebook's
Psychosocial section to the sibling house style (short description + bash +
Available techniques), dropping impl details and outdated content (MHFA/ALGEE,
create_conversation_scorer, YAML rubric internals, brittle converter counts).
Regenerated airt.ipynb and re-ran the minimal cell.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b7009abc-fe0b-4d7e-a39a-971a396e9eef
@rlundeen2 rlundeen2 changed the title [BREAKING] MAINT: Re-migrate Psychosocial scenario to per-sub-harm cross-product [BREAKING] MAINT: Re-migrate Psychosocial scenario to per-subharm cross-product Jul 16, 2026
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