Skip to content

Commit ab68979

Browse files
Use declarative category identity metadata (#177)
* Document verbosity category and workspace.cif layout * Reorganize development documentation structure * Tighten workspace migration plan for autonomous implementation * Consolidate ADR index into single table * Add loop category key identity ADR and plan * Add declarative category identity resolution * Declare category identities on current items * Persist explicit constraint identifiers * Update ADR for declarative category identity * Verify declarative category identity behavior
1 parent aa44c46 commit ab68979

78 files changed

Lines changed: 2648 additions & 1821 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/copilot-instructions.md‎

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@
3434
- One class per file when substantial; group small related classes.
3535
- No `**kwargs` — use explicit keyword arguments.
3636
- No string-based dispatch (e.g. `getattr(self, f'_{name}')`); write
37-
named methods (`_set_sample_form`, `_set_beam_mode`).
37+
named methods (`_set_sample_form`, `_set_beam_mode`). Narrow framework
38+
metadata lookups are allowed when the attribute name is a class-level
39+
declaration, is not user input, and is validated in one central place;
40+
for example, `CategoryItem._category_entry_name`.
3841
- Public attrs are either editable (getter+setter property) or read-only
3942
(getter only). For internal mutation of read-only props, use a private
4043
`_set_<name>` method, not a public setter.
@@ -77,7 +80,7 @@
7780
## Testing
7881

7982
- Every new module, class, or bug fix ships with tests. See
80-
`docs/dev/architecture.md` §10 for the full strategy.
83+
`docs/dev/adrs/accepted/test-strategy.md` for the full strategy.
8184
- Unit tests mirror the source tree:
8285
`src/easydiffraction/<pkg>/<mod>.py` →
8386
`tests/unit/easydiffraction/<pkg>/test_<mod>.py`. Verify with
@@ -102,8 +105,11 @@
102105

103106
- Before any structural/design change (new categories, factories,
104107
switchable-category wiring, datablocks, CIF serialisation), read
105-
`docs/dev/architecture.md` and follow documented patterns. Localised
106-
bug fixes or test updates need only this file.
108+
`docs/dev/adrs/index.md` and the relevant accepted ADRs. Localised bug
109+
fixes or test updates need only this file.
110+
- Development documentation lives under `docs/dev/`. Use
111+
`docs/dev/adrs/index.md` as the architecture and decision navigation
112+
surface; there is no separate `architecture.md` source of truth.
107113
- Project is in beta: no legacy shims, no deprecation warnings — update
108114
tests and tutorials to the current API.
109115
- Minimal diffs; don't reformat working code. Fix only what's asked;
@@ -112,7 +118,10 @@
112118
resolves them.
113119
- Never remove or replace existing functionality without explicit
114120
confirmation — highlight every removal and wait for approval.
115-
- When renaming, grep the entire project (code, tests, tutorials, docs).
121+
- When renaming or auditing usages, search the entire project (code,
122+
tests, tutorials, docs). Use `git grep -n` because all contributors
123+
have Git; do not assume `rg` is installed. If `git grep` is
124+
unavailable, fall back to `find ... -type f` plus `grep -n`.
116125
- Each change is atomic and single-commit-sized: make one change,
117126
suggest the commit message, then stop and wait for confirmation.
118127
- When in doubt, ask.
@@ -137,34 +146,45 @@
137146

138147
Non-trivial changes use a two-phase workflow:
139148

140-
- **Phase 1 — Implementation.** Code, docs, and architecture updates
141-
only. Do not create or run tests unless the user explicitly asks. When
142-
done, present for review and iterate until approved.
149+
- **Phase 1 — Implementation.** Code and docs updates only. Update ADRs
150+
when the change affects architecture or documented decisions. Do not
151+
create or run tests unless the user explicitly asks. When done,
152+
present for review and iterate until approved.
143153
- **Phase 2 — Verification.** Add/update tests, then run `pixi run fix`,
144154
`pixi run check`, `pixi run unit-tests`, `pixi run integration-tests`,
145155
`pixi run script-tests`.
146156

147157
Notes:
148158

149-
- `pixi run fix` regenerates `docs/dev/package-structure-*.md`
150-
automatically — never edit those by hand. Don't review auto-fixes;
151-
accept and move on. Then `pixi run check` until clean.
159+
- `pixi run fix` regenerates `docs/dev/package-structure/full.md` and
160+
`docs/dev/package-structure/short.md` automatically — never edit those
161+
by hand. Don't review auto-fixes; accept and move on. Then
162+
`pixi run check` until clean.
152163
- Open issues / design questions / planned improvements live in
153-
`docs/dev/issues_open.md` (priority-ordered). On resolution, move to
154-
`docs/dev/issues_closed.md` and update `architecture.md` if affected.
164+
`docs/dev/issues/open.md` (priority-ordered). On resolution, move to
165+
`docs/dev/issues/closed.md` and update the relevant ADR or
166+
`docs/dev/adrs/index.md` if affected.
155167

156168
### Planning
157169

158170
When asked to create a plan:
159171

172+
- Start the plan by referencing this file:
173+
`.github/copilot-instructions.md`. State any deliberate exception to
174+
these instructions in the plan itself.
160175
- First gather enough repository context to make the plan concrete. Ask
161176
all ambiguous or unclear questions in one concise batch; record
162177
unresolved questions in the plan if the user wants it saved before
163178
answering them.
164-
- Save plans as `docs/dev/plan_<feature-name>.md` (lowercase,
165-
dash-separated, e.g. `plan_background-refactor.md`). Use the same
166-
`<feature-name>` for the implementation branch
167-
(`feature/<feature-name>`). Do not push the branch unless asked.
179+
- Save plans as `docs/dev/plans/<feature-name>.md` (lowercase,
180+
dash-separated, e.g. `docs/dev/plans/background-refactor.md`). When a
181+
plan implements one ADR, use the same slug as the ADR file; for
182+
example, `docs/dev/adrs/suggestions/foo.md` maps to
183+
`docs/dev/plans/foo.md`. If a plan has no corresponding ADR or spans
184+
multiple ADRs, choose a concise feature slug and list all related ADRs
185+
in the plan. Use the same `<feature-name>` for the implementation
186+
branch (`feature/<feature-name>`). Do not push the branch unless
187+
asked.
168188
- Include a status checklist with `[ ]` items; mark `[x]` as completed
169189
during implementation.
170190
- Apply the two-phase workflow (Phase 1 implementation, Phase 2
@@ -184,6 +204,9 @@ When asked to create a plan:
184204
files likely to change, decisions already made, open questions,
185205
verification commands for Phase 2, and a short suggested commit
186206
message or branch name when useful.
207+
- Before saving a plan, verify that referenced files, directories,
208+
scripts, and task names exist locally when that is practical. If a
209+
referenced tool is optional or missing, include an available fallback.
187210
- End every plan with a "Suggested Pull Request" section containing a
188211
short PR title and a brief end-user-oriented description. Keep this
189212
section non-technical enough for scientists and other users to
File renamed without changes.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# ADR: Two-Level Category Parameter Access
2+
3+
## Status
4+
5+
Accepted.
6+
7+
## Date
8+
9+
2026-05-17
10+
11+
## Group
12+
13+
Core model.
14+
15+
## Context
16+
17+
EasyDiffraction models CIF concepts as datablocks, categories, category
18+
collections, and parameters. Users need predictable navigation paths
19+
from a structure or experiment to any parameter.
20+
21+
## Decision
22+
23+
Use at most two navigation levels from a datablock to a parameter:
24+
25+
```python
26+
structure.cell.length_a = 3.88
27+
experiment.instrument.setup_wavelength = 1.494
28+
structure.atom_sites['Si'].adp_iso = 0.47
29+
experiment.background['10'].y = 170
30+
```
31+
32+
The general forms are:
33+
34+
- `DATABLOCK.CATEGORY_ITEM.PARAMETER`
35+
- `DATABLOCK.CATEGORY_COLLECTION[ITEM_ID].PARAMETER`
36+
37+
Categories are flat siblings under their owner. A category must not own
38+
another category of a different type.
39+
40+
## Consequences
41+
42+
API paths remain short, regular, and close to CIF category structure.
43+
Nested category designs are rejected because they make parameter access
44+
depth depend on the domain area and obscure the CIF-like model.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# ADR: Development Documentation Structure
2+
3+
## Status
4+
5+
Accepted.
6+
7+
## Date
8+
9+
2026-05-17
10+
11+
## Group
12+
13+
Documentation.
14+
15+
## Context
16+
17+
Development notes, ADRs, roadmap material, package-structure snapshots,
18+
and issue backlogs were all kept directly under `docs/dev` or under
19+
mixed-case directories. That made the development documentation harder
20+
to scan and created several competing naming conventions.
21+
22+
The repository also contains `docs/docs`, which is the MkDocs source for
23+
published user documentation. Development-only material should not be
24+
mixed into that tree unless it is intentionally published.
25+
26+
## Decision
27+
28+
Keep development-only documentation under `docs/dev`.
29+
30+
Use this structure:
31+
32+
```text
33+
docs/dev/
34+
|-- index.md
35+
|-- adrs/
36+
| |-- index.md
37+
| |-- accepted/
38+
| `-- suggestions/
39+
|-- issues/
40+
| |-- open.md
41+
| `-- closed.md
42+
|-- package-structure/
43+
| |-- full.md
44+
| `-- short.md
45+
|-- plans/
46+
`-- roadmap/
47+
`-- ROADMAP.md
48+
```
49+
50+
Use lowercase directory names for new development-doc folders. Keep
51+
`ROADMAP.md` uppercase because it may later be copied into published
52+
user documentation where the conventional filename is useful.
53+
54+
Use `docs/dev/adrs/index.md` as the architecture and decision navigation
55+
surface. Do not keep a separate architecture overview that duplicates
56+
ADR content.
57+
58+
## Consequences
59+
60+
- Development documentation remains under the documentation tree without
61+
being part of the published MkDocs source by default.
62+
- ADRs have one entry point for architecture navigation and separate
63+
accepted and proposed areas.
64+
- Package-structure snapshots have stable, script-friendly paths.
65+
- Roadmap publication can later be implemented as a build-time copy from
66+
`docs/dev/roadmap/ROADMAP.md` into `docs/docs`.
File renamed without changes.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# ADR: Enum-Backed Closed Value Sets
2+
3+
## Status
4+
5+
Accepted.
6+
7+
## Date
8+
9+
2026-05-17
10+
11+
## Group
12+
13+
Core model.
14+
15+
## Context
16+
17+
Many attributes accept a finite set of values: experiment axes, factory
18+
tags, fit modes, calculators, minimizers, and rendering engines.
19+
String-only dispatch is hard to grep and easy to mistype.
20+
21+
## Decision
22+
23+
Represent every finite closed set with a `(str, Enum)` class.
24+
25+
Use enum members as the internal source of truth for validation,
26+
dispatch, default rules, and descriptions. User-facing setters may
27+
accept either enum members or their string values, but internal code
28+
compares against enum members.
29+
30+
## Consequences
31+
32+
Finite choices are discoverable, type-checkable, and greppable.
33+
Validation can use enum membership instead of hand-written string
34+
patterns.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# ADR: Factory Contracts and Metadata
2+
3+
## Status
4+
5+
Accepted.
6+
7+
## Date
8+
9+
2026-05-17
10+
11+
## Group
12+
13+
Factories.
14+
15+
## Context
16+
17+
Many domain categories have multiple implementations, and some currently
18+
have only one implementation but may gain more later. Construction,
19+
default selection, compatibility filtering, and supported-option display
20+
need a common contract.
21+
22+
## Decision
23+
24+
Every category that can be constructed by framework code is created
25+
through a factory, even when it currently has only one implementation.
26+
27+
Concrete factory-created classes carry metadata appropriate to their
28+
role:
29+
30+
- `type_info` for stable tag lookup and user descriptions.
31+
- `compatibility` for experiment-axis compatibility where relevant.
32+
- `calculator_support` for calculation-engine support where relevant.
33+
34+
Child rows that only exist inside a collection do not carry factory
35+
metadata; the collection carries the metadata.
36+
37+
Factory registration is triggered by explicit imports in package
38+
`__init__.py` files.
39+
40+
## Consequences
41+
42+
Construction, default resolution, support tables, and compatibility
43+
filtering stay uniform. Single-implementation categories are ready for
44+
future alternatives without changing the public construction pattern.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# ADR: Factory Tag Naming
2+
3+
## Status
4+
5+
Accepted.
6+
7+
## Date
8+
9+
2026-05-17
10+
11+
## Group
12+
13+
Naming.
14+
15+
## Context
16+
17+
Factory tags are persisted and used for public selection. Inconsistent
18+
abbreviations or ordering would make saved files and user code harder to
19+
read.
20+
21+
## Decision
22+
23+
Canonical factory tags are:
24+
25+
- lowercase
26+
- hyphen-separated
27+
- semantically ordered from general to specific
28+
- unique within a factory
29+
30+
Use standard abbreviations:
31+
32+
| Concept | Abbreviation |
33+
| ------------------- | ------------ |
34+
| Powder | `pd` |
35+
| Single crystal | `sc` |
36+
| Constant wavelength | `cwl` |
37+
| Time-of-flight | `tof` |
38+
| Bragg scattering | `bragg` |
39+
| Total scattering | `total` |
40+
41+
Context-local aliases are allowed when the owning object already
42+
disambiguates the choice, for example `pseudo-voigt` inside a CWL
43+
experiment.
44+
45+
## Consequences
46+
47+
Saved tags are stable and greppable, while user-facing APIs can remain
48+
short where context makes the canonical prefix redundant.
File renamed without changes.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# ADR: Free-Flag CIF Encoding
2+
3+
## Status
4+
5+
Accepted.
6+
7+
## Date
8+
9+
2026-05-17
10+
11+
## Group
12+
13+
Persistence.
14+
15+
## Context
16+
17+
Fitting needs to persist whether a parameter is fixed or free. A
18+
separate free-parameter list would duplicate state already attached to
19+
individual parameter values and could become stale.
20+
21+
## Decision
22+
23+
Encode a parameter's free/fixed status in the CIF value uncertainty
24+
syntax:
25+
26+
```text
27+
3.89 fixed
28+
3.89(2) free with estimated standard deviation
29+
3.89() free without estimated standard deviation
30+
```
31+
32+
Do not persist a separate list of free parameters as the source of
33+
truth.
34+
35+
## Consequences
36+
37+
Each parameter carries its own fit-state information in the same place
38+
as the value. CIF round-trips are simpler because there is no separate
39+
state table to reconcile.

0 commit comments

Comments
 (0)