From 8314cee29c2bab179bead25688a81187937c3086 Mon Sep 17 00:00:00 2001 From: Evgeniy Unzhakov Date: Sat, 16 May 2026 19:51:37 +0300 Subject: [PATCH] refactor: restructure metadata files for context efficiency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Shrink global AGENTS.md: 153 → 56 lines (−63%) Removed: git workflow, TDD, overthinking guards, code style, reasoning protocol Kept: personality, git basics, thinking levels, general principles, backend - Create project AGENTS.md: 71 lines Added: stack/commands, GitHub Flow git workflow, Conventional Commits, TDD (Python-specific), quality gates, debug verification - Trim CONVENTIONS.md: 161 → 68 lines (−58%) Removed: verbose examples, redundant unit convention section, lengthy SpectrumComponent code example - Delete DEVELOPMENT.md: 238 lines → 0 (migrated to AGENTS.md) Setup/release checklist removed (not agent concerns) Git workflow, TDD, quality gates, notebook QC, debug verification all migrated to AGENTS.md - Update README.md project structure Total per-session metadata: 552 → 195 lines (−65%) --- AGENTS.md | 71 +++++++++++++++ CONVENTIONS.md | 165 ++++++++-------------------------- DEVELOPMENT.md | 238 ------------------------------------------------- README.md | 9 +- 4 files changed, 113 insertions(+), 370 deletions(-) create mode 100644 AGENTS.md delete mode 100644 DEVELOPMENT.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f252446 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,71 @@ +# Agent Instructions — beta-spectrum + +High-precision beta decay spectrum calculator. Extracts shape factor C(W) from ⁹⁹Tc beta spectrum to parametrize g_V coupling. + +## Stack & Commands + +``` +pytest # all tests +nbmake notebooks/ # execute notebooks as tests +black --check . # formatting +ruff check . # linting +mypy . # type checking (strict) +bs_pnpi --nuclide Tc99 -vv --output ./output/verification.csv # debug verification +``` + +Install: `source ~/.pyenv/sci/bin/activate && pip install -e ".[dev]"` + +## Git Workflow (GitHub Flow) + +- **Never commit directly to `main`.** Always branch: `git checkout -b dev/` +- **Atomic commits** with **Conventional Commits** format: + - `feat:`, `fix:`, `docs:`, `style:`, `refactor:`, `perf:`, `test:`, `chore:` + - Imperative mood, present tense, under 72 chars + - WIP commits fine on dev branches — squash before final merge +- **Commit each logical change** — don't wait for green. Use `git add -p`. +- **Rebase over merge** for linear history: `git rebase main` before merge. +- Delete branch locally + remotely after merge. + +## TDD + +Test-first by default. For new classes/functions: write failing test first. + +- **RED** — failing test defining desired behavior +- **GREEN** — minimal code to pass +- **REFACTOR** — clean up, confirm tests still pass + +State which phase you're in. Name phases explicitly. + +### Python Testing Conventions + +- Tests mirror package structure: `beta_spectrum/components/foo.py` → `tests/physics/test_foo.py` +- Shared fixtures in `tests/conftest.py` +- Classes organized by feature area (e.g., `TestComponentBasicProperties`) +- Descriptive names: `test___` +- Include implementation-level assertions (type checks, pre/postconditions) +- Use `hypothesis` for property-based tests where applicable +- Physics tests verify: physical constraints at thresholds, positivity, monotonicity, numerical stability + +## Quality Gates + +All must pass before merge: + +```bash +pytest +nbmake notebooks/ +black --check . +ruff check . +mypy . +``` + +Run individually to identify failures. + +## Debug Verification (Final Step) + +After quality gates pass, run: + +```bash +bs_pnpi --nuclide Tc99 -vv --output ./output/verification.csv --plot ./output/verification.png --log-file ./output/debug.log 2>&1 | tee ./output/debug_stdout.log +``` + +Verify parameter consistency across all components. Save artifacts to `./output/`. diff --git a/CONVENTIONS.md b/CONVENTIONS.md index e0a295b..7e369cd 100644 --- a/CONVENTIONS.md +++ b/CONVENTIONS.md @@ -1,161 +1,68 @@ # Project Conventions -This file defines the physical, mathematical, and architectural conventions that govern code correctness and consistency across the project. +Physical, mathematical, and architectural conventions governing code correctness. -## 1. Natural Units System +## 1. Natural Units -All internal representations, calculations, and definitions use natural units: +All internal calculations use natural units: ``` m_e = ℏ = c = 1 ``` -where `m_e` is the electron rest mass. This is the fundamental unit for energy, mass, momentum, and time throughout the codebase. +`m_e` is the electron rest mass. Fundamental unit for energy, mass, momentum, and time. ## 2. Energy Representation -### Core Principle +**Internal:** total energy `W` in m_e units (`W = 1.0` = rest mass, `W > 1.0` = kinetic). -Internal calculations use natural units (m_e). External interfaces (API signatures, plots, human-readable output) use eV-based units (MeV or keV). +**External API:** human-readable MeV/keV. Check the unit suffix in parameter names: +- `_MeV` suffix → value is in MeV +- `_keV` suffix → value is in keV (detector params only) +- No suffix on energy → value is in m_e units (internal) -### API Signatures (Input) +### Conversion -Use human-readable MeV for parameters that come from databases or literature: - -- `endpoint_MeV` — Q-value / endpoint energy in MeV -- `detector_sigma_a_keV` — resolution in keV -- `detector_tau_keV` — tail decay constant in keV - -### Internal Representation - -All internal computations use **total energy W in m_e units**: - -``` -W = T_to_W(T_MeV) # T (kinetic) in MeV → W (total) in m_e -W = T + 1.0 # W = T/m_e + 1 (since m_e = 1 in m_e units) -``` - -- `W = 1.0` corresponds to zero kinetic energy (rest mass) -- `W > 1.0` corresponds to kinetic energy -- All internal functions accept and operate on `W` -- Endpoint W0 is always `T_to_W(endpoint_MeV)` - -### Output and Display - -Convert back to eV units for anything intended for human perception: - -- Plots: x-axis in keV or MeV (kinetic energy) -- ASCII output, CSV export: kinetic energy in keV or MeV -- Log messages, error messages: use keV/MeV with context - -```python -kinetic_keV = (W - 1.0) * ME_KEV # W in m_e → kinetic energy in keV -kinetic_MeV = (W - 1.0) * ME_ME # W in m_e → kinetic energy in MeV -``` - -### Conversion Helpers - -All conversions and constants must go through the central utilities: +Always use central utilities — never hardcode constants or manual arithmetic: ```python from beta_spectrum.utils import T_to_W, W_to_T from beta_spectrum.constants import ME_MEV, ME_KEV, ALPHA, MP_MEV ``` -- Never hardcode physical constants — import from `constants.py` -- Never use manual arithmetic for unit conversion — use `T_to_W()`, `W_to_T()` -- Never mix MeV and m_e units in the same calculation +## 3. SpectrumComponent Design -## 3. Energy Unit Convention +All spectral components follow a common interface: -### MeV Throughout - -All energy parameters in the public API use **MeV** as the standard unit: - -- `endpoint_MeV` — always in MeV -- `e_step_MeV` — always in MeV -- `detector_sigma_a_keV` — in keV (detector-specific, exception noted) -- `detector_tau_keV` — in keV (detector-specific, exception noted) - -Detector parameters use keV because detector resolutions are typically specified in keV in the literature. All other energies use MeV. - -### CLI Unit Convention - -All CLI energy parameters use MeV unless explicitly marked otherwise: - -- `--e-step` — MeV (default: 0.001) -- `--sigma` — keV (detector resolution, default: 1.0) -- `--tau` — keV (tail decay constant, default: 5.0) - -### Consistency Rule - -When reading or writing values, always check the unit suffix in the parameter name: -- `_MeV` suffix → value is in MeV -- `_keV` suffix → value is in keV -- No suffix on energy parameter → value is in m_e units (internal) - -## 4. SpectrumComponent Design - -All spectral components (Fermi function, screening, radiative correction, etc.) follow a common interface: - -- **Stateless or minimally stateful** — no mutable state that depends on input -- **Vectorized** — accept and return `np.ndarray`, support array broadcasting -- **Consistent energy variable** — always use `W` (total energy in m_e units) internally +- **Stateless or minimally stateful** — no mutable state depending on input +- **Vectorized** — accept/return `np.ndarray`, support broadcasting +- **Consistent energy variable** — always `W` (total energy in m_e units) internally - **Callable interface** — implement `__call__(W)` for uniform usage -- **Return correction factor** — output is a multiplicative factor, typically ~0.1 to 10 +- **Return correction factor** — multiplicative factor, typically ~0.1 to 10 -```python -class MyComponent(SpectrumComponent): - def __init__(self, param1: float, param2: float): - self.param1 = param1 - self.param2 = param2 +## 4. Logging - def __call__(self, W: np.ndarray) -> np.ndarray: - # All internal computation uses W in m_e units - return ... -``` +- **No verbosity (default):** errors and warnings only +- **`-v` (INFO):** source selection, component init, workflow steps, output locations +- **`-vv` (DEBUG):** all INFO + detailed internals (parameters, ranges, evaluation counts) -## 5. Logging Convention +Each `SpectrumComponent` logs: +- **INFO** at init: component name + key parameters +- **DEBUG** at evaluation: energy point count, input/output ranges -### Verbosity Levels +## 5. Nuclear Data Notation -- **No verbosity (default)**: Only errors and warnings -- **`-v` (INFO)**: Shows source selection, component initialization, workflow steps, and output locations -- **`-vv` (DEBUG)**: Shows all INFO messages plus detailed internals of each spectrum component (parameters, input/output ranges, evaluation counts) +- Element: `Tc`, `Ru`, `U` +- Nuclide: `Tc99`, `Ru99`, `U238` +- Decay: `Tc99 -> Ru99` (parent → daughter) +- CSV headers use element notation: `# nuclide: Tc99 -> Ru99 (Z=43->44)` -### Component Logging +## 6. Physics Testing Guidelines -Each `SpectrumComponent` logs at two levels: +When testing physics components, verify: -- **INFO** at initialization: Component name and key parameters -- **DEBUG** at evaluation: Number of energy points, input/output value ranges - -This allows debugging without cluttering normal output. - -## 6. Nuclear Data Notation - -### Element and Nuclide Notation - -- Element symbol: `Tc`, `Ru`, `U`, etc. (from atomic number) -- Nuclide notation: `Tc99`, `Ru99`, `U238` (element symbol + mass number) -- Decay notation: `Tc99 -> Ru99` (parent -> daughter) - -### CSV Header Convention - -CSV metadata headers use element notation for readability: - -``` -# nuclide: Tc99 -> Ru99 (Z=43->44) -``` - -This provides both the human-readable notation and the machine-parseable Z values. - -## 7. Physics-Specific Testing Guidelines - -When writing tests for physics components, verify the following: - -- **Physical constraints** — values at thresholds, endpoints, and boundaries must match known physics behavior -- **Monotonicity / positivity** — spectrum components should not produce unphysical negative values; monotonicity should match physical expectations -- **Shape correctness** — output shape must match input shape (vectorized operation) -- **Type safety** — components accept and return `np.ndarray` -- **Numerical stability** — no NaN or inf in the physical energy range, except where physically expected (e.g., below kinematic threshold, near soft-photon endpoint divergence) +- **Physical constraints** — values at thresholds, endpoints, boundaries match known physics +- **Positivity** — no unphysical negative values +- **Shape correctness** — output shape matches input (vectorized) +- **Type safety** — components accept/return `np.ndarray` +- **Numerical stability** — no NaN/inf in physical range (except where physically expected) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md deleted file mode 100644 index aaedb62..0000000 --- a/DEVELOPMENT.md +++ /dev/null @@ -1,238 +0,0 @@ -# Development Workflow - -## 1. Setup - -Do not attempt system wide pip installations. Use virtual environment 'sci'. -Default venv location: `~/.pyenv/`. - -```bash -source ~/.pyenv/sci/bin/activate -pip install -e ".[dev]" -``` - -## 2. Git Workflow - -### Before Starting Any Work - -```bash -git status # MUST show clean working tree -git fetch origin -git rebase origin/main # update to latest main -``` - -If `git status` is not clean, commit or stash existing changes first. Never begin new work on a dirty working tree. - -### Branch Strategy - -```bash -git checkout main -git checkout -b dev/ # always create a new branch -``` - -Branch naming: `dev/` (e.g., `dev/recoil-correction`) - - -### Merging Rules - -- All work happens on `dev/*` branches — never commit directly to `main` -- Tests MUST pass before any merge attempt -- Merging to `main` requires a pull request with passing CI checks -- If tests fail, fix them on the dev branch — do NOT merge broken code -- Before merging always update TODO.md and README.md - -## 3. Test-Driven Development - -### TDD Cycle - -1. **Red** — write a failing test that expresses the desired behavior -2. **Green** — implement minimal code to make the test pass -3. **Refactor** — clean up code while keeping all tests green - -Commit work-in-progress changes to development branch. - -### Test Conventions - -- Tests live in `tests/` with the same structure as `beta_spectrum/` -- New component `beta_spectrum/components/foo.py` → test file `tests/test_foo.py` -- Use shared fixtures from `tests/conftest.py` (`W_low`, `W_mid`, `W_high`, `W_full`, `large_W`) -- Organize tests in classes by feature area (e.g., `TestComponentBasicProperties`, `TestComponentEdgeCases`) -- Each test class should have a docstring explaining what is being tested and why -- Use descriptive test names: `test_threshold_vanishes`, not `test_1` - -### What to Test - -See [`CONVENTIONS.md`](CONVENTIONS.md) §4 for physics-specific testing guidelines (physical constraints, positivity, numerical stability). - -For general test structure, use the conventions below. - -## 4. Quality Gates - -All of the following MUST pass before merging to `main`: - -```bash -pytest # all tests pass -nbmake notebooks/ # execute and validate notebooks -black --check . # code formatting -ruff check . # linting -mypy . # type checking (strict mode) -``` - -These are configured in `pyproject.toml`. Run them individually to identify failures. - -### Notebook Quality Control - -Notebooks in `notebooks/` are executed as pytest tests using `nbmake`. This ensures: - -- All code cells execute without errors -- Full error traces are available for debugging -- Plots are extracted for LLM-based visual analysis - -**Workflow:** - -1. Write notebooks with explicit figure saving: - ```python - fig.savefig('_plots/notebook_name_cell{N}.png', dpi=100, bbox_inches='tight') - from IPython.display import display, Image - display(Image(filename='_plots/notebook_name_cell{N}.png')) - ``` - -2. Execute and extract plots: - ```bash - python scripts/run_notebooks.py notebooks/ - ``` - -3. Send extracted plots to LLM for visual review: - ``` - @notebooks/_plots/notebook_name_cell4.png - ``` - -4. Run full quality gates: - ```bash - pytest notebooks/ --nbmake # or just `pytest` (includes notebooks/) - ``` - -______________________________________________________________________ - -### 4.5. Debug Verification (Final Step of Each Dev Iteration) - -After all quality gates pass, run a **debug-level verification** as the final step of every development iteration. This catches configuration mismatches, missing parameter propagation, and silent logic errors before merging. - -**Purpose:** Verify that all parameters (endpoint energy, energy grid, Z, A, physical constants) are consistent throughout the pipeline, and that every spectrum component emits sufficient debug logging for explicit comparison. - -**Procedure:** - -1. **Run `bs_pnpi` with `-vv` (DEBUG logging) and output to `./output/`:** - ```bash - bs_pnpi --nuclide Tc99 -vv --output ./output/verification.csv - ``` - -2. **Capture full debug output to a log file for analysis:** - ```bash - bs_pnpi --nuclide Tc99 -vv --output ./output/verification.csv --log-file ./output/debug.log 2>&1 | tee ./output/debug_stdout.log - ``` - -3. **Verify consistency of key parameters in the debug output:** - - | Parameter | What to check | Where to find it | - |---|---|---| - | `endpoint_MeV` | Matches expected Q-value | CLI dry-run, config creation, energy grid | - | `Z_parent` / `Z_daughter` | Consistent across all components | Component init logs | - | `A_number` | Consistent across all components | Component init logs | - | `e_step_MeV` | Matches grid size × (endpoint - e_step) | Energy grid creation | - | `W0` (endpoint in natural units) | `W0 = 1.0 + endpoint_MeV / m_e` | PhaseSpace init | - | Physical constants | `m_e = 0.51099895` MeV, `α = 1/137.036` | Constants module, Fermi function | - | Energy grid bounds | `e_step` to `endpoint - e_step` | `get_energy_grid()` output | - -4. **Verify each component's debug logging:** - - Every enabled component must log its initialization parameters and a representative evaluation. Check the debug output for entries like: - - ``` - DEBUG ... Initializing PhaseSpace: W0=1.57664, transition_type=A, m_e=1.0 - DEBUG ... Evaluating PhaseSpace at 294 energy points - DEBUG ... PhaseSpace range: [min=..., max=...] - ``` - - Required log entries per component: - - | Component | Must log | - |---|---| - | `PhaseSpace` | `W0`, `transition_type`, `m_e`, `m_nu`, energy range | - | `FermiFunction` | `Z`, `A`, `α`, Coulomb approximation used | - | `FiniteSizeL0` | `Z`, `A`, nuclear radius `R`, L0 approximation | - | `ChargeDistributionU` | `Z`, `A`, charge radius, U correction range | - | `ScreeningCorrection` | `Z_parent`, screening model, S(Z,W) range | - | `ExchangeCorrection` | `Z_parent`, Hayen coefficients used, X(Z,W) range | - | `RadiativeCorrection` | `W0`, `δ_r` formula, resummation flag, `delta_cut` value | - -5. **Report any missing logging:** - - If a component's debug output does not allow explicit verification of its parameters or computed range, **add logging to that component** before the iteration is considered complete. The goal is that a developer (or an LLM) reading the debug log can reconstruct every parameter and verify correctness without reading source code. - -6. **Save debug artifacts to `./output/`:** - - After verification, ensure all artifacts are in `./output/`: - - `debug_stdout.log` — full stdout+stderr from `bs_pnpi -vv` - - `debug.log` — log file output (if `--log-file` was used) - - `verification.csv` — the spectrum CSV with metadata header - - `verification.png` — analysis plot (if `--plot` was used) - - These files serve as a **verifiable record** of the last working state and can be used for regression comparison. - -**Example verification command:** - -```bash -# Full debug run with all outputs -bs_pnpi --nuclide Tc99 -vv \ - --output ./output/verification.csv \ - --plot ./output/verification.png \ - --log-file ./output/debug.log 2>&1 | tee ./output/debug_stdout.log - -# Quick parameter extraction from debug log -grep -E '(Initializing|Evaluating|W0=|Z=|endpoint|e_step|PhaseSpace|Fermi|FiniteSize|Screening|Exchange|Radiative)' ./output/debug_stdout.log -``` - -**Success criteria:** - -- [ ] All parameters (Z, A, endpoint, e_step, W0) appear consistently in debug output -- [ ] Each enabled component logs its initialization parameters -- [ ] Each enabled component logs its evaluation energy range -- [ ] Physical constants match expected values -- [ ] No silent parameter coercion or unit conversion errors detected -- [ ] All artifacts saved to `./output/` - -**If any check fails:** - -1. Add missing debug logging to the component -2. Fix any parameter mismatch -3. Re-run the verification until all checks pass -4. Only then consider the iteration complete - -## 5. Agent Instructions - -When working on this project, agents must: - -1. **Read existing tests first** — understand patterns before writing new ones -2. **Follow existing conventions** — match test style, fixture usage, and class organization -3. **Never commit changes** without explicit user request -4. **Never merge branches** without explicit user request -5. **Verify `git status` is clean** before starting any file modifications -6. **Work on a dev branch** — create `dev/` and switch to it -7. **Run quality gates** after making changes and report results -8. **Update docs** when changing public API or adding features -9. **Run debug verification** (`bs_pnpi -vv`) as the final step of each iteration, saving all artifacts to `./output/` and verifying parameter consistency across all components - -## 6. Release Checklist - -- [ ] All tests pass (`pytest`) -- [ ] Code is formatted (`black --check`) -- [ ] No lint errors (`ruff check`) -- [ ] Type checks pass (`mypy`) -- [ ] Debug verification passes (`bs_pnpi -vv`) — all parameters consistent, all components logged -- [ ] Debug artifacts saved to `./output/` (debug_stdout.log, verification.csv, etc.) -- [ ] Update version in `pyproject.toml` -- [ ] Update `Development Status` section in `README.md` -- [ ] Update `TODO.md` marking corresponding items as complete. -- [ ] Commit changes -- [ ] Create git tag: `git tag v` -- [ ] Push to remote diff --git a/README.md b/README.md index 9e92b53..c9545e0 100644 --- a/README.md +++ b/README.md @@ -75,10 +75,13 @@ beta_shape_pnpi/ │ ├── test_fitter.py # Curve fitter tests │ ├── test_cw_extractor.py # C(W) extraction tests │ └── test_nuclear_data.py # paceENSDF + JSON input tests (23 tests) -└── data/ - ├── exchange_coeff.csv # Tabulated coefficients for X(Z,W), Z=2..120 - └── custom_input_example.json # Sample JSON input file +├── data/ +│ ├── exchange_coeff.csv # Tabulated coefficients for X(Z,W), Z=2..120 +│ └── custom_input_example.json # Sample JSON input file ├── output/ # Test run outputs (gitignored except .gitkeep) +├── AGENTS.md # Agent instructions: stack, git workflow, TDD, quality gates +├── CONVENTIONS.md # Physics conventions: natural units, energy representation, component design +├── TODO.md # Development roadmap ``` ______________________________________________________________________