Repository navigation
Re/03 core schema - #3
Merged
Merged
Conversation
…t it (A61, A62) Closes the A56/A57 obligation: powderline.symmetry no longer references a gateway. The _translation_error() helper is gone; every raise is powderline.exceptions.SymmetryError(PowderLineError, ValueError). - TOPAS writer: one _symmetry() helper wraps its three symmetry calls, converts SymmetryError to TopasTranslationError (chained) and applies TOPAS's own rejection of the rhombohedral :R setting (same message). - easydiffraction policy/builder catch SymmetryError instead of TopasTranslationError (no longer importing the TOPAS gateway); the policy rejects :R itself. - Core resolve_space_group/site_dof/adp_dof accept :R (A62); cell_constraints refuses :R explicitly (its tied angles are not expressible as CellRules). Gateway-raised error types are unchanged. Direct callers of powderline.symmetry see SymmetryError, and :R is accepted by the resolver. Both are recorded in the devkit deliberate-changes table (A34). Test IDs relabelled: three test_topas_symmetry *_raises_translation_error tests became *_raises_symmetry_error; the :R test was split in two. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ime until re/04) - Parameter models (A20, A32, A71, A72): RefinableParameter [value, flag] and BoundedRefinableParameter [value, flag, min, max]. A 4-list where bounds are unsupported is an error naming the field. The Structure* variants allow value null (start from the phase structure's value). Strict boolean flags; list-only JSON shape; the JSON Schema describes the arrays. - XRDData: the 0.26.0 validators ported verbatim; unit metadata (A19). - FitRange [min, max]: max > min, finite; check_fit_range_within_data for engine payloads (A68). ChebyshevBackground ported, strict flag. - CoreRecipe frame: schema_name "<engine>.<workflow>", core/engine schema versions (core checked against SUPPORTED_CORE_SCHEMAS, A40), metadata JSON-serializable and capped at METADATA_MAX_BYTES = 1 MiB (A64). - check_element_symbol: a bare symbol spelled exactly as in gemmi's table; charged types rejected, never stripped (A63). - extra='forbid' everywhere (A21). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ort_matrix() (A40, A65) Gateways declare engine_schema_version / supported_engine_schemas / requires_core_schema (a specifier, or a mapping per engine-schema range) as capabilities() keys. check_engine_schema_version raises ValueError so that engine schema models can call it from a validator. support_matrix() walks the registry (engine-free); the in-repo gateways are undeclared until re/04-06. powderline.support_matrix is re-exported, outside __all__. The import-block test now imports schema_core and compat and calls support_matrix() with GSAS-II and easydiffraction blocked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…antic's ValidationError (A70) All recipe checks live in the schema models, so pydantic's own ValidationError reports every problem with its location; a wrapper only duplicated it (and would have broken except-ValidationError callers, superseding A60). The class was unused outside its unit test. A new test shows a SymmetryError raised in a validator joining the aggregated error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a 0.21-0.26 archive (A37) Core 1.0.0 is documented as in development and not yet used. The engine sections are placeholders for re/04-06. The existing history is kept verbatim below, with headings moved one level down. A banner states that the runtime still validates schema 0.26.0 until re/07. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ct site DOF classification analyze_site(space_group, xyz) is the core schema's site validation (KI-03): - the space group must name its setting (two-origin :1/:2, rhombohedral :H/:R; A62); - symmetry images closer than 5e-6 put the operation in the stabilizer (>= 6 decimals declare a special position); - an image between 5e-6 and 2e-3 raises SymmetryError naming the exact special position and its multiplicity (ambiguous band); - canonical coordinates: the barycenter of the stabilizer images, with fixed axes set to their exact fraction (denominator <= 48); `adjusted` reports a difference above 1e-12; - multiplicity = |G| / |stabilizer|, with consistency checks; coordinate and Uij DOF classification. DOF classification fix (P1): FIXED is now a row test on the stabilizer projector, FREE a column test. The old column-only test misread trigonal and hexagonal sites, whose rotations are not orthogonal in fractional coordinates (e.g. 6h (x, 2x, 1/4) gave x FIXED). The legacy site_dof/adp_dof (0.26.0 TOPAS writer warnings) share the corrected helper. Recorded as a deliberate change. tests/test_symmetry_characterization.py compares multiplicity, coordinate DOF and Uij DOF with GSAS-II's SytSym/GetCSxinel/GetCSuinel for all 230 space groups (GSAS-II symbol verified per group by matching the orbits), plus canonicalization, ambiguous-band and committed-example checks. With the old column test reinstated, 13 trigonal/hexagonal groups fail. Skipped without GSAS-II. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on (A77, A78) - check_cell(space_group, cell): the metric tensor must be invariant under every group rotation; compared with the group-averaged cell within CELL_TOL = 1e-9 (float noise only). Errors name each parameter and its symmetric value. Covers all crystal systems incl. monoclinic unique axes and rhombohedral :R. - check_uij(space_group, xyz, uij): U must be invariant under the site stabilizer (R U R^T, the GSAS-II convention). Within UIJ_TOL = 1e-6 A^2 the symmetric values are returned with adjusted=True; beyond that, SymmetryError. - Canonical coordinates and symmetric Uij use the least-change (orthogonal) projection onto the symmetric subspace, anchored at the stabilizer barycenter. The Reynolds average alone is oblique on hexagonal/trigonal axes and moved free components (e.g. U11 on 6h). Changes <= 1e-12 snap back to the stated value; SiteAnalysis gains `adp`. - tests/test_symmetry_core.py (core-only, no GSAS-II); the characterization canonicalization tests now assert exact values (the previous np.allclose silently allowed rtol=1e-5) and the coupled least-change result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re (A35, A62-A63, A69, A73-A78) PhaseStructure validates the structure once, in core: - explicit space-group setting (A62); - cell lengths > 0, angles in (0, 180), no volume (A75), cell consistent with the group (A77); - exact bare element symbols (A63); - occupancy 0..1 (A76); - ADP 'Uiso' with Uiso or 'Uaniso' with all six Uij, Uij consistent with the site symmetry, adjusted within 1e-6 A^2 (A78); - per-atom analyze_site: ambiguous band = error, stated Multiplicity cross-checked (A69), special-position coordinates replaced by their exact canonical values (A73). Every adjustment becomes a StructuredWarning (special_position_adjusted / adp_symmetry_adjusted, field_path relative to the structure), available from warnings(). The site analyses are available from site(label). All atom problems are reported together in one error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lders Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… location (A70) Review of PR #3 (S2, F1, N2): - All of an atom's problems are reported: a wrong Multiplicity no longer skips that atom's Uaniso check. - Each problem is a separate pydantic error at its field: unit_cell, atoms.<label> (position), atoms.<label>.Multiplicity, atoms.<label>.Uaniso, raised together as one ValidationError (ValidationError.from_exception_data). Locations get the enclosing path when PhaseStructure is embedded in an engine model, also from JSON. The atom label is now in the location, not repeated in the message. - Canonicalization no longer modifies a caller-supplied Atom: adjusted atoms are copies (model_copy). - Docstring + SCHEMA_HISTORY: problems are reported per field, once the individual fields are valid (pydantic skips model validators after a field error). Tests: one atom with two problems; cell + position + multiplicity locations; nested JSON locations; caller Atom untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… band message, compat input check Review of PR #3 (N1, N4-N8, N10): - check_element_symbol suggests a spelling only for case/whitespace differences (' Fe' -> 'Fe'); gemmi's prefix reading ('Nax' -> Na) is no longer offered as a fix (N1). - ChebyshevBackground rejects non-finite coefficients, like every other numeric core field (N7). - analyze_site's ambiguous-band error names the special position and its multiplicity only when the nearby operations form a group (new _is_group); otherwise it says "a special position" instead of printing a non-multiplicity (N10). - compat.required_core_schemas raises ValueError (not AttributeError) for a requires_core_schema that is neither a specifier nor a mapping; support_matrix() documents that malformed declarations raise (N8). - Docstrings: UnitCell cites A75 (N4); oblique projector singular values (N5); topas/errors.py no longer says symmetry raises it (N6). Tests: element hints; non-finite coefficients; _is_group; band message; compat non-mapping. The compat first-match test now has two matching keys in both orders (it could not tell first-wins from highest-bound-wins); the misleadingly named picks_highest_version_match is replaced by skips_non_matching_keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ema/symmetry tests Review of PR #3 (N3): - The 11 bare pytest.raises(ValidationError) in test_schema_core (strict flags, null values) now assert the exact (location, type) of every error, so they cannot pass on the wrong field. - The cubic b != a test asserted '"b" in msg' (always true); it now checks "b = 4.2 (symmetric value" and the unit_cell location. - "Returned unchanged" checks use == instead of abs(...) < 1e-15 (check_uij, canonical 1/3 and 2/3, free U11 on 6h); the code returns exact values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…c core fields (A80) Review of PR #3 (S1). pydantic's default lax mode read "0.25" and true as numbers (x: true -> 1.0, Multiplicity: true -> 1), against A73 and the generated JSON Schema. Every numeric core field now uses one of two types, exported for the engine schemas: - CoreFloat = Annotated[float, Strict()]: any number (int, float, numpy scalar); a string, bytes or a boolean is a float_type error; - CoreInt: a whole number (4 or 4.0, as JSON Schema's integer, numpy ints included); a string, bytes or a boolean is an int_type error, 4.5 an int_from_float error. Covers parameter values and bounds, FitRange, XRDData arrays, Chebyshev coefficients and num_coefficients, the unit cell, atom coordinates, occupancy, Uiso, Uaniso and Multiplicity. Values that were accepted as numbers keep their value; the JSON Schema is unchanged. metadata stays free-form (A21). The legacy 0.26.0 schema is untouched. Tests: every numeric field rejects "0.5", "1", true, false and accepts int / numpy float / numpy int as a float; whole-number rules for both integer fields; quoted numbers rejected from JSON. SCHEMA_HISTORY states the rule. 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/03 — core schema 1.0.0, symmetry validation, version compatibility
Adds the engine-free core schema 1.0.0 (
powderline.schema_core), the coresite/cell/ADP symmetry validation (
powderline.symmetry), and thedeclared schema-version compatibility machinery (
powderline.compat).Nothing at runtime routes through the new models yet: the gsasii/topas/
easydiffraction engine schemas adopt them in re/04–06, and the 0.26.0 path is
unchanged until re/07. Not a gate branch.
Decisions: A61–A80 (master plan §3; A60 superseded by A70). Tolerance rules
signed off by the maintainer (A69, A73, A76–A78).
What's in it
powderline.symmetryraises a coreSymmetryError(PowderLineError, ValueError); the TOPAS writer and theeasydiffraction policy/builder convert it to their own error types (their
behavior is unchanged, incl. rejecting
:R), so no core module references agateway.
RecipeValidationErrorremoved: invalid recipes raise pydantic'sValidationError.schema_core(A19–A21, A32, A63–A64, A68, A71–A72, A75–A80):RefinableParameter[value, flag]andBoundedRefinableParameter[value, flag, min, max](list-only JSON;Structure*variants allow anull value);
XRDData,FitRange(+check_fit_range_within_data),ChebyshevBackground;UnitCell,Atom,PhaseStructure;CoreRecipeframe:schema_name, core/engine schema versions,metadata≤ 1 MiB;extra='forbid'everywhere; exact bare element symbols (chargedtypes rejected); occupancy 0–1; no
volume; numbers must be JSON numbers(
CoreFloat/CoreInt; strings and booleans rejected, A80).5e-6 ≤ d < 2e-3 is an error. Accepted positions are canonicalized
(least change): fixed coordinates become exact fractions. Each adjustment
is reported as a structured warning.
stated.
and reported, larger ones are errors.
field (
unit_cell,atoms.<label>,.Multiplicity,.Uaniso).test; the old test misread trigonal/hexagonal sites). It also applies to
the legacy
site_dof/adp_dof(deliberate change Re/03 core schema #3).compat(A40, A65): gateways declareengine_schema_version,supported_engine_schemas,requires_core_schemaincapabilities();check_engine_schema_versionenforces them (never version arithmetic);powderline.support_matrix()lists them (engine-free).docs/SCHEMA_HISTORY.mdrestructured into core + per-enginesections with the 0.21–0.26 archive kept verbatim; core 1.0.0 rules
documented.
Behavior changes vs v0.1.1 (devkit
tasks/deliberate-changes.md)powderline.symmetrygetSymmetryErrorinstead ofTopasTranslationError; gateway error types are unchanged.:R; TOPAS and easydiffractionstill reject it, with the same message.
trigonal/hexagonal sites (corrected classification); emitted INP values
are unchanged.
Verification
gateways/gsasii/,kicker.py,_code_hash.jsonorexamples/; the code-hash test is green at everycommit.
SytSym/GetCSxinel/GetCSuinelvs core forall 230 space groups. Exhaustive probe: 14368 points, 0 disagreements.
Reinstating the old classification fails 13 groups.
(baseline 637p/4s; only the 6 deliberate baseline IDs changed); easydiff
env 55 passed.
schema_core,compatandsupport_matrix(); touched files are UTF-8/LF.-Wdocs build (intersphinxdownloads blocked).
Review
An independent Opus 5.5 review found no blockers. Its findings (S1 strict
numbers, S2 complete per-atom reporting, F1 per-field error locations, nits
N1–N10) are all fixed in the last four commits (
8f7991f,f964558,b5cea07,9ad114c). No known issues filed. Record: devkitdossiers/multi-engine/tasks/re03-review-record.md.For later branches
CoreRecipe+PhaseStructure, useCoreFloat/CoreInt, declare the A65 capability keys, and surfacePhaseStructure.warnings().:1origin.= p/q;for fixed special coordinates anddecides how to tie Uij.
Uanisofor easydiffraction.multiplicities.
Assisted-by: claude-code:claude-opus-5-5
Assisted-by: claude-code:claude-sonnet-4-5
Assisted-by: claude-code:claude-haiku-4-5