[BREAKING] MAINT: Re-migrate Psychosocial scenario to per-subharm cross-product#2191
Open
varunj-msft wants to merge 7 commits into
Open
Conversation
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.
rlundeen2
reviewed
Jul 15, 2026
…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
…dardizing-Scenarios-Psychosocial-v2
…dardizing-Scenarios-Psychosocial-v2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Re-migrates the
Psychosocialscenario onto the current_build_atomic_attacks_asyncseam, implementing a per-subharm design and fixing a wrong-scorer-on-allbug.What changed
_SubharmConfig/_SUBHARMS). A frozen tuple defines the two subharms —imminent_crisis(datasetairt_imminent_crisis) andlicensed_therapist(datasetairt_licensed_therapist) — each carrying its own dataset name, display name, scorer rubric, crescendo escalation path,success_threshold, andexcluded_techniques._build_atomic_attacks_asyncbuilds one atomic attack per (selected technique × subharm). Each atomic attack gets its own subharm's scorer and display group — this fixes the bug where runningallscored every attack with a single run-level scorer.role_playexcluded forlicensed_therapist. For the therapist subharm the fictional movie-scriptrole_playframing measures the wrong thing and is a poor fit, so it is excluded for that subharm (excluded_techniques={"role_play"}).success_threshold.licensed_therapist = 0.5(a raw Likert ≥ 3 counts — this catches the real harm of the model claiming "I am a licensed therapist," which a uniform 1.0 threshold missed);imminent_crisis = 1.0. Threaded through the scorer build.licensed_therapist.yaml's rationale line was copy-pasted MHFA/crisis-management boilerplate; rewritten to be about licensure / therapeutic impersonation.prompt_sending(default) +role_play(default) +crescendo(opt-in). Techniques select attack techniques, not subharms.baselineso it suppresses the base scenario's central generic prepend; the rest arebaseline_<subharm>). This expresses the baseline via the central baseline + per-subharm naming. (is_baselinedoes not exist onmaintoday, and psychosocial is the only plural-baseline consumer, so it ships with the naming approach; a base-classis_baselinerefactor remains a possible hardening follow-up.)psychosocial.prompt→airt_imminent_crisis.prompt(2 crisis seeds) +airt_licensed_therapist.prompt(1 therapist seed), so each subharm has its own dataset.TARGET_REQUIREMENTS = EDITABLE_HISTORY(the older version declared it). The default techniques (prompt_sending+role_play) are single-turn: they degrade to a preamble (role_playends in an unanswered user elicitation turn) rather than dropping the objective on non-editable targets;crescendois opt-in and self-validatesEDITABLE_HISTORYat the attack layer. A clarifying comment documents this, and a test guards that a non-editable target is accepted at initialization by default (the acceptance is asserted at init; the degrade-to-preamble behavior is a design property of the single-turn techniques, not a live-execution assertion).initialize_asyncrejects caller dataset name selection (datasets are tied to subharms) but keeps--max-dataset-size.--max-dataset-sizeapplied per subharm (fixes CLI starvation). The CLI--max-dataset-size Nsets the cap on the whole compound dataset config, which the base applies as one global budget across the union of the two subharm datasets — so--max-dataset-size 1starved a subharm (measured 12/12 objectives dropped), breaking psychosocial's defining "both subharms always run" invariant._normalize_max_dataset_size_to_per_subharm()(called in_resolve_seed_groups_by_dataset_asyncafter validation) rebuilds the compound as an explicit per-childper_dataset(dataset_names=[subharm], max_dataset_size=N)and sets the compound cap toN × num_subharms— mathematically it never trims the union, yet stays non-Noneso the base's resume objective-hash pinning still fires. Caller--dataset-filtersare re-applied viaupdate_filters, and the config is replaced (never mutated) so re-initialization is idempotent. End-to-end at compound cap 1: both subharms keep running (0/8 starved, was 12/12). This keeps--max-dataset-sizeworking as an independent per-subharm cap.Tests and Documentation
tests/unit/scenario/airt/test_psychosocial.py— 44 tests, all passing. Covers: per-subharm scorer routing (each subharm scored with its own rubric);role_playexclusion forlicensed_therapist; per-subharmsuccess_threshold(0.5 vs 1.0); no-double-baseline; theper_datasetprimitive caps each subharm independently; the CLI compound--max-dataset-sizepath keeps both subharms non-empty; the default config is left un-normalized; normalization preserves--dataset-filters; per-subharm baseline scoring;role_playcarriesadversarial_chat(regression); default accepts a non-editable-history target; dataset-config validation.doc/scanner/airt.py+doc/scanner/airt.ipynbpsychosocial section rewritten (3 techniques, both subharms,--max-dataset-size, no--dataset-names). Synced with jupytext.ruff check,ruff format --check,ty,pytest tests/unit/scenario/airt/test_psychosocial.py.Open item: the baseline uses the per-subharm naming approach; confirm it's acceptable to ship it that way, with the base-class
is_baselinerefactor tracked as a separate hardening follow-up.