Repository navigation
Re/02 registry shared core - #2
Merged
Merged
Conversation
PowderLineError base plus RecipeValidationError, GatewayNotInstalledError,
EngineNotAvailableError (also an ImportError, A52), EngineVersionError (A44)
and EngineExecutionError; StructuredWarning = {code, message, field_path}.
Engine-free. The registry and gateways raise these from the next commits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… to an engine-free module (verbatim) Both functions read only the recipe (no GSAS-II references), but lived in kicker.py, which imports GSAS-II at module top. Moving them verbatim to gateways/gsasii/validation.py lets the gsasii gateway's schema layer validate without GSAS-II installed (A51). kicker re-exports both, so powderline.validate and every powderline.kicker.* import are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moves src/powderline/topas/symmetry.py to src/powderline/symmetry.py, ending the easydiff -> topas cross-adapter import. Importers updated (topas writer, easydiff policy + builder, test_topas_symmetry); no shim. One deviation from a verbatim move (A56): the module's relative 'from .errors import TopasTranslationError' cannot survive the move, and an absolute import at module top is circular (topas/__init__ -> writer -> symmetry). The import now happens inside the two raising functions, so the raised type is unchanged. Interim: re/03 makes core symmetry raise a core error that each gateway translates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pure-numpy standard fit statistics (A23), computed once in core. R factors in percent, GoF/chi2_red dimensionless (A55). N = points inside the fit-range mask with w > 0 (A55; evidence in the dossier's tasks/fitstats-n-convention.md); P is the engine-reported varied-parameter count, supplied by each gateway (A41/A45). Created + unit-tested only; gateways adopt it in re/04-06. The LaB6 characterization test documents how it differs from GSAS-II's own numbers: Rwp/GoF agree; GSAS-II's wRmin omits P; N differs by one edge point. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…files Engine-free writers for refined_parameters.csv, <phase>_unit_cell_report.csv, fit_profile.txt and <phase>_peak_list_report.csv: they own file naming, column order, header, delimiter and quoting (csv QUOTE_MINIMAL, like pandas), UTF-8 + LF; number formatting stays with the caller. Created + unit-tested only (byte-identical round-trip of all 37 committed GSAS-II references); gateways adopt them in re/04-06 with byte-identical checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…her routed through it - powderline.registry: lazy discovery of the 'powderline.gateways' entry-point group (ep.load on first get), register_gateway() escape hatch, GatewayNotInstalledError, and a clear stale-install-metadata error when the group is empty. Gateway = frozen dataclass (A54); check_engine_version() enforces the PEP 440 ENGINE_VERSION_SPEC as a hard error (A44). - Engine-free gateway.py per gateway (gsasii, topas, easydiff): schema layer validate()/capabilities() runs with no engine installed (A50); runtime run() wraps today's kicker.run / run_topas_recipe / run_easydiffraction_recipe unchanged, importing the engine lazily. Real runs check the engine version (GSASII.__version__; configured TOPAS version, skipped when unset; easydiffraction distribution version) with a gateway-level allow_unsupported_engine_version bypass (A53); a missing engine raises EngineNotAvailableError (an ImportError, A52). Specs: GSAS-II ==5.7.9, TOPAS >=7,<8, easydiffraction >=0.20.1,<0.21. - powderline.engine.run: old engine= names map 1:1 to registry names; public signature and per-engine outputs unchanged (LaB6 gsasii + topas outputs byte-identical to ae415c8). - pyproject: [project.entry-points."powderline.gateways"]; packaging>=22 declared in pyproject + pixi.toml (lock: requires_dist only). CLAUDE.md notes the reinstall needed after entry-point edits. - Tests: registry (escape hatch, laziness, error texts, real entry points, PYTHONPATH=src mode) + gateways (specs, validate, version checks, dispatcher forwarding, import-block schema-only path with GSAS-II/easydiffraction blocked). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…G1 KI-13) The A56 relocation re-imported TopasTranslationError lazily in only two of the four raising functions; cell_constraints and site_dof would have raised NameError on their (unreachable with real gemmi groups) fallthrough paths. All six raise sites now use _translation_error(), the module's single reference to a gateway, so re/03's switch to a core error is one line (A57). Tests force all three defensive paths; an undefined-name probe over every module changed since v0.1.1 reports none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…G1 nit) NaN > 0 is False, so a NaN weight was silently dropped from N instead of raising as documented. Weights are now checked over the whole fit range before the w > 0 filter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…est hygiene (G1 nits) - Every gateway's validate() takes the same explicit keywords (A59); topas and easydiffraction previously took none, so registry.get(n).validate(r, verbose=True) raised TypeError for them. Tests assert the signature and the call through the registry for all three. - The dispatcher-routing test restores the registry via a fixture, even on failure (it cleaned up only on success). - Recipe reads in test_gateways pin encoding="utf-8" (Windows, G3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tadata (watch) Filed by the G1 review (as KI-14; renumbered because the review's KI-13, a re/02 regression, was fixed before merge and never entered the register). Decision A58: entry points stay the only discovery path; re/08 adds install-health guidance, re/10 documents the re-install step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
re/02 — gateway registry + shared core modules (G1 gate branch)
This branch doesn't change behaviour.
powderline.run(recipe, output_dir, engine=...)works exactly as before, with the sameengine=names, schema 0.26.0 and outputs. The difference is that dispatch now goes through a plugin registry. The branch also adds the shared core modules that the schema branches (re/03–06) build on. G1 gate: passed (independent reviewer session, no blockers); the review's findings are fixed in this branch.What's in it
powderline.registry)powderline.gatewaysentry-point group:ep.load()runs only when a gateway is first requested.register_gateway()escape hatch for tests and development.GatewayNotInstalledError, plus a clear "re-install" error when no entry points are found at all.Gatewaydataclass (A54).gateways/gsasii/gateway.py,topas/gateway.py,easydiff/gateway.py.validate,capabilities): runs with no engine installed.run): thin wrappers over today'skicker.run/run_topas_recipe/run_easydiffraction_recipe, importing the engine lazily.ENGINE_VERSION_SPECand fails hard if it's out of range (EngineVersionError, A44). Specs: GSAS-II==5.7.9, TOPAS>=7,<8, easydiffraction>=0.20.1,<0.21. There's a test-only bypass,allow_unsupported_engine_version(A53).EngineNotAvailableError, which is also anImportError, so existingexcept ImportErrorcode keeps working (A52).validate(recipe, *, verbose=False)(A50, A59).powderline.engine.run) maps the oldengine=names 1:1 to registry names. Its public signature is unchanged.symmetrypromoted fromtopas/to corepowderline.symmetry, ending the easydiff → topas import. The move is verbatim except for one thing: the error is created by a lazy_translation_error()helper, because a top-level import would be circular. This is a temporary fix; re/03 replaces it with a core error (A56/A57).exceptions.py: the error types plus the{code, message, field_path}warning shape (A60 confirmsRecipeValidationErrorsubclassesValueError).fitstats.py: Rwp and Rexp in percent, GoF and reduced χ² unitless. N counts only in-range points with weight > 0; P is the parameter count reported by the engine (A41, A45, A55).reports.py: shared writers for the four standard report files. They reproduce all 37 committed GSAS-II references byte for byte.validate+validate_simulation_mode_parametersnow live in an engine-freegateways/gsasii/validation.py;kickerre-exports both (A51).[project.entry-points."powderline.gateways"]added.packaging>=22declared in pyproject + pixi.toml. Thepixi.lockdiff is a singlerequires_distline.pixi reinstall powderlineis needed after editing entry points.known_issues.mdKI-13 (watch): every engine, including the default gsasii, now depends on entry-point metadata written at install time. We keep entry points as the only discovery path (A58).Commits (10 on
ae415c8)fe49fd0b9767a7b3eec02a42a8a79c241098d98e6d4e1bc1b04b136833f510ca84fd39Verification
ae415c8→ 637 passed / 4 skipped ata84fd39.test_easydiff_*give 54 passed, unchanged. Run with the new registry, gateway, symmetry and fitstats tests: 152 passed / 2 skipped.run(engine="gsasii")andrun(engine="topas")on LaB6 produce byte-identical outputs atae415c8and on this branch. GSAS-II also matches the committed references withinregression-tolerance._code_hash.jsonunchanged.examples/untouched.v0.1.1.G1 gate
An independent reviewer session gave PASS on every checklist item (evidence reproduced, not taken on trust). Findings were resolved on this branch with the maintainer (A57–A60):
symmetry.pywould have hitNameErroron unreachable paths (a regression fromAn independent reviewer session gave PASS on every checklist item (evidence reproduced, not taken on trust). Findings were resolved on this branch with the maintainer (A57–A60):
symmetry.pywould have hitNameErroron unreachable paths (a regression from the move). Fixed before merge.watch).Evidence: devkit
dossiers/multi-engine/tasks/re02-g1-record.md.Obligations for later branches
symmetry_translation_error()helper with a core error that each gateway translates into its own type (a deliberate behaviour change for the A34 table). Keep A59'svalidatecontract.validate(), adoptfitstats/reports, and supply P forfitstats.ENGINE_VERSION_SPEC; add install-health guidance for KI-13.allow_unsupported_engine_versioninto the compatibility suite.Decisions: master plan §3 A50–A60. Devkit record commits:
72a319c,c31768d,0b8cd50.🤖 Generated with Claude Code