Skip to content

Adds bead.config.compose, FORCED_CHOICE, gallery v0.4.0 wiring (0.5.0)#6

Merged
aaronstevenwhite merged 4 commits into
mainfrom
feat/config-compose-and-gallery
May 12, 2026
Merged

Adds bead.config.compose, FORCED_CHOICE, gallery v0.4.0 wiring (0.5.0)#6
aaronstevenwhite merged 4 commits into
mainfrom
feat/config-compose-and-gallery

Conversation

@aaronstevenwhite
Copy link
Copy Markdown
Collaborator

Description

Three coupled changes plus a wave of correctness fixes:

  1. bead.config.compose — a didactic-grounded config composer
    replaces the hand-rolled loader. Generic over any dx.Model
    schema; supports the full OmegaConf interpolation grammar
    (${section.field}, ${.x} / ${..x} relative,
    ${a.b[0]} / ${a.b.0} list indexing, ${a.${b}} nested,
    \${literal} escape, cycle detection) and the standard
    resolver suite (oc.env, oc.select, oc.decode,
    oc.deprecated, oc.create, oc.dict.keys, oc.dict.values).
    defaults: [...] composition, TOML support, schema-driven
    strict-merge, and repeatable --set KEY=VALUE CLI overrides
    on every bead subcommand. Bead-specific resolvers
    (${bead.path:rel}, ${bead.anchor:name[,attr]}) live in
    bead.config.resolvers. Structured for future extraction as a
    standalone didacticonf distribution: only merge.py imports
    didactic.

  2. ScaleType.FORCED_CHOICE — first-class N-AFC support
    throughout family_to_item_template, the active-learning
    model registry, and AnchorSpec.scale_type (response space =
    positional labels like ("first", "second"), per-item
    alternatives on each Item).

  3. Gallery v0.4.0 wiringgallery/eng/argument_structure/
    gets a new protocol.py module that materializes the live
    AnnotationProtocol from config.yaml. create_2afc_pairs.py
    threads the anchor name into every pair's item_metadata;
    generate_deployment.py and simulate_pipeline.py build
    their ItemTemplate via family_to_item_template instead of
    literal prompts; make validate-protocol gates make data.

Fixes

  • Save/load bug in 8 model subclasses: the base trainer
    popped state-only fields from config.json before
    _load_model_components, but each subclass re-read the file
    and undid the pop. _load_model_components(load_path, config_dict)
    now takes the cleaned dict.
  • ResourceWarning file-handle leaks in
    bead.cli.items_factories: for line in open(...)
    read_text().splitlines() in 6 sites.
  • ValidationError: PosixPath is not JSON serializable in
    the Lightning trainer: self.config.model_dump()
    json.loads(self.config.model_dump_json()) so Paths / Enums
    flatten to JSON shape.
  • UserWarning: participant_ids provided but mode='fixed' in
    ~40 mixed-effects tests: dropped redundant participant_ids
    args in fixed-mode tests; switched length-validation tests to
    random_intercepts so the validation path is actually
    exercised.
  • spaCy 3.8.11 ↔ Python 3.14 import crash: upgraded to
    spaCy 3.8.13 / pydantic 2.13.4.

Motivation

Two coupled needs surfaced together:

  • The gallery still used v0.3.0-era idioms (hard-coded prompts,
    ad-hoc JATOS-result loading, dict-shaped config). It should be
    the reference implementation for the protocol stack the
    framework now ships.
  • The hand-rolled config loader (no interpolation, no defaults
    composition, no CLI overrides) was the actual blocker for any
    non-trivial declarative workflow. The cleanest answer was a
    custom composer grounded in didactic rather than pulling in
    OmegaConf and accepting a second data-structure paradigm.

The fixes were uncovered while running the full suite under
-W error to verify the new code didn't regress anything.

Fixes #

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • Tests (adding or updating tests)

Checklist

  • I have read the CONTRIBUTING guidelines
  • My code follows the project's style guidelines
  • I have run uv run ruff check . and uv run ruff format .
  • I have run uv run pyright with no errors (pre-existing pyright noise in untouched modules persists; new files are clean)
  • I have added tests that prove my fix/feature works
  • All tests pass (uv run pytest tests/) (3553 passed under -W error, excluding the slipt-dep tests/behavioral/ directory; the long-running gallery/eng/argument_structure/tests/test_simulation.py::TestRunSimulation BERT-training tests hang in this local environment as they did pre-branch)
  • I have updated documentation as needed

Testing

  • tests/config/compose/ — 43 new tests cover the parser/evaluator,
    built-in resolvers, custom-resolver registration, and the
    end-to-end compose pipeline against a FakeSchema.
  • tests/protocol/test_encoding.py, tests/protocol/test_items_bridge.py
    FORCED_CHOICE paths through encoding + items bridge.
  • gallery/eng/argument_structure/tests/test_protocol.py — config
    AnnotationProtocol round trip, scale type, prompt agreement,
    model registry routing.
  • gallery/eng/argument_structure/tests/test_simulation.py
    updated to the protocol-driven template and Item.model_validate_json.
  • Full suite (minus tests/behavioral/ which requires the optional
    slopit dep): 3553 passed under -W error in ~32 minutes.

Screenshots (if applicable)

N/A

…(0.5.0)

Replaces the hand-rolled config loader with a generic, didactic-grounded
composer that supports the full OmegaConf interpolation grammar
(absolute / relative / bracketed / dotted-index / nested references,
`\${literal}` escape, cycle detection) and the standard resolver suite
(`oc.env`, `oc.select`, `oc.decode`, `oc.deprecated`, `oc.create`,
`oc.dict.keys`, `oc.dict.values`). Adds `defaults: [...]` composition,
TOML support, schema-driven strict-merge, and CLI-style
`--set KEY=VALUE` overrides on every `bead` subcommand. Bead-specific
resolvers (`\${bead.path:rel}`, `\${bead.anchor:name[,attr]}`) live in
`bead.config.resolvers`. `bead.config.load_config` is now a thin
wrapper that binds the schema to `BeadConfig`. The subpackage is
structured for a future extraction into a standalone `didacticonf`
distribution: only `merge.py` imports `didactic`.

Adds `ScaleType.FORCED_CHOICE` so N-AFC tasks (response space =
positional labels like `("first", "second")`, per-item alternatives
on each `Item`) are first-class through `family_to_item_template`
and the active-learning model registry. `AnchorSpec.scale_type`
exposes the override declaratively.

Wires `gallery/eng/argument_structure/` to the protocol layer: new
`protocol.py` module materializes the live `AnnotationProtocol` from
`config.yaml`; `create_2afc_pairs.py` threads the anchor name into
every pair's `item_metadata`; `generate_deployment.py` and
`simulate_pipeline.py` build their `ItemTemplate` via
`family_to_item_template`; `make validate-protocol` gates data
generation; `tests/test_protocol.py` covers the config-to-protocol
round trip and bridges to items / models.

Fixes a save/load bug where every model subclass re-read `config.json`
after the base trainer had already popped its state-only fields,
causing `model_validate` to reject them. The base `_load_model_components`
now takes the cleaned `config_dict` so subclasses never re-read the
file (8 model files updated). Replaces leaky `for line in open(...)`
patterns in `bead.cli.items_factories` and switches the lightning
trainer to `json.loads(self.config.model_dump_json())` so Paths /
Enums flatten correctly into `ModelMetadata.training_config`.

Bumps spaCy to 3.8.13 / pydantic to 2.13.4 (Python 3.14 import
compatibility). Updates docs (`configuration.md`, `protocols.md`,
training codeblock) and both READMEs (top-level Quick Start + gallery
protocol section). Bumps version to 0.5.0.
@aaronstevenwhite aaronstevenwhite merged commit ea5fc0b into main May 12, 2026
8 checks passed
@aaronstevenwhite aaronstevenwhite deleted the feat/config-compose-and-gallery branch May 12, 2026 17:24
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.

1 participant