Adds bead.config.compose, FORCED_CHOICE, gallery v0.4.0 wiring (0.5.0)#6
Merged
Merged
Conversation
…(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.
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
Three coupled changes plus a wave of correctness fixes:
bead.config.compose— a didactic-grounded config composerreplaces the hand-rolled loader. Generic over any
dx.Modelschema; 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 standardresolver suite (
oc.env,oc.select,oc.decode,oc.deprecated,oc.create,oc.dict.keys,oc.dict.values).defaults: [...]composition, TOML support, schema-drivenstrict-merge, and repeatable
--set KEY=VALUECLI overrideson every
beadsubcommand. Bead-specific resolvers(
${bead.path:rel},${bead.anchor:name[,attr]}) live inbead.config.resolvers. Structured for future extraction as astandalone
didacticonfdistribution: onlymerge.pyimportsdidactic.ScaleType.FORCED_CHOICE— first-class N-AFC supportthroughout
family_to_item_template, the active-learningmodel registry, and
AnchorSpec.scale_type(response space =positional labels like
("first", "second"), per-itemalternatives on each
Item).Gallery v0.4.0 wiring —
gallery/eng/argument_structure/gets a new
protocol.pymodule that materializes the liveAnnotationProtocolfromconfig.yaml.create_2afc_pairs.pythreads the anchor name into every pair's
item_metadata;generate_deployment.pyandsimulate_pipeline.pybuildtheir
ItemTemplateviafamily_to_item_templateinstead ofliteral prompts;
make validate-protocolgatesmake data.Fixes
popped state-only fields from
config.jsonbefore_load_model_components, but each subclass re-read the fileand undid the pop.
_load_model_components(load_path, config_dict)now takes the cleaned dict.
ResourceWarningfile-handle leaks inbead.cli.items_factories:for line in open(...)→read_text().splitlines()in 6 sites.ValidationError: PosixPath is not JSON serializableinthe Lightning trainer:
self.config.model_dump()→json.loads(self.config.model_dump_json())so Paths / Enumsflatten to JSON shape.
UserWarning: participant_ids provided but mode='fixed'in~40 mixed-effects tests: dropped redundant
participant_idsargs in fixed-mode tests; switched length-validation tests to
random_interceptsso the validation path is actuallyexercised.
spaCy 3.8.13 / pydantic 2.13.4.
Motivation
Two coupled needs surfaced together:
ad-hoc JATOS-result loading, dict-shaped config). It should be
the reference implementation for the protocol stack the
framework now ships.
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 errorto verify the new code didn't regress anything.Fixes #
Type of Change
Checklist
uv run ruff check .anduv run ruff format .uv run pyrightwith no errors (pre-existing pyright noise in untouched modules persists; new files are clean)uv run pytest tests/) (3553 passed under-W error, excluding the slipt-deptests/behavioral/directory; the long-runninggallery/eng/argument_structure/tests/test_simulation.py::TestRunSimulationBERT-training tests hang in this local environment as they did pre-branch)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_CHOICEpaths through encoding + items bridge.gallery/eng/argument_structure/tests/test_protocol.py— config→
AnnotationProtocolround 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.tests/behavioral/which requires the optionalslopitdep): 3553 passed under-W errorin ~32 minutes.Screenshots (if applicable)
N/A