Skip to content

Commit b2f1c75

Browse files
committed
docs: align src/AGENTS.md and STYLEGUIDE.md with explicit-dataflow refactor
Update src/AGENTS.md source tree to the rtm/optics/spectrum/setup/cache layout and document the explicit-dataflow rule (banned god-object identifiers, allowed named data owners, *const reads / single named write target) enforced by scripts/linting/check-explicit-dataflow-signatures.py. Replace the STYLEGUIDE.md function-map example that taught the now-banned Workspace naming with a solveReflectance example using *TransportWorkArrays, and add a dataflow section to the recognized function-map sections.
1 parent dc9538a commit b2f1c75

2 files changed

Lines changed: 67 additions & 31 deletions

File tree

STYLEGUIDE.md

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,48 +64,53 @@ explanatory comments above `fn`, even for small private helpers or methods.
6464
For methods inside a struct, title the box `StructName.fnName`.
6565

6666
```zig
67-
fn layerResolvedSolveWithWorkspace(...) Result {
68-
// layerResolvedSolveWithWorkspace ------------------------------------------------------------------------|
69-
// Runs layer-resolved transport for one high-resolution sample. Steps: |
67+
pub fn solveReflectance(
68+
angles: ViewAngles,
69+
surface_albedo: f64,
70+
layers: []const layer_depths.LayerOptics,
71+
level_sources: []const source_levels.SourceLevel,
72+
phase: phase_table.PhaseTable,
73+
config: controls.SolveConfig,
74+
work: *TransportWorkArrays,
75+
) Error!ReflectanceResult {
76+
// solveReflectance ---------------------------------------------------------------------------------------|
77+
// Dispatch one explicit transport solve for one high-resolution sample. Steps: |
7078
// |
71-
// 1. build attenuation for this geometry and correction setting |
72-
// 2. loop retained Fourier terms: |
73-
// basis |
74-
// -> layer matrices |
75-
// -> transported fields |
76-
// -> Fourier reflectance term |
77-
// 3. add Fourier weight * Fourier reflectance term into total reflectance |
78-
// 4. add requested surface, aerosol-depth, and pressure Jacobians |
79-
// 5. stop when the Fourier tail is below the threshold |
79+
// 1. choose direct surface or layer-resolved LABOS transport |
80+
// 2. require integrated-source rows before accepting pressure Jacobians |
81+
// 3. build the borrowed curved-grid view for pseudo-spherical top paths |
82+
// 4. return reflectance plus the fixed-order Jacobian vector |
8083
// |
8184
// hot path |
8285
// repeated : every retained Fourier term |
83-
// costly : basis build |
84-
// layer-matrix build |
86+
// costly : layer-matrix build |
8587
// scattering-order propagation |
8688
// reflectance integral |
8789
// Jacobian : aerosol weighting, only when requested |
88-
// memory : workspace buffers reused when this route allows |
90+
// |
91+
// dataflow |
92+
// inputs : explicit scalars, slices, and named physics tables |
93+
// reads : geometry and phase basis borrowed as *const |
94+
// writes : caller-owned TransportWorkArrays only, never a broad Context or Workspace |
8995
// |
9096
// calls |
9197
// buildLayerMatrices |
9298
// propagateScatteringOrders |
9399
// integrateReflectance |
94100
// |
95101
// math |
96-
// total reflectance += Fourier weight * Fourier reflectance term |
97-
// |
98-
// Fourier weight |
99-
// = 1 when m = 0 |
100-
// = 2 * cos(m * relative_azimuth) when m > 0 |
101-
// |
102-
// m : Fourier index |
102+
// direct path = exp(-tau / max(mu0, 0.05)) * exp(-tau / max(muv, 0.05)) |
103+
// reflectance = surface_albedo * direct path |
103104
// --------------------------------------------------------------------------------------------------------|
104105
```
105106

106107
Use sections only when they help. Good sections are `hot path`, `calls`,
107-
`math`, and `instrumentation`. If a function has many trace or telemetry blocks,
108-
the function map should say what they measure and why they exist.
108+
`math`, `dataflow`, and `instrumentation`. If a function has many trace or
109+
telemetry blocks, the function map should say what they measure and why they
110+
exist. In the hot folders (`src/optics`, `src/rtm`, `src/spectrum`,
111+
`src/retrieval`) use a `dataflow` section to state what the signature reads
112+
(explicit scalars, slices, `*const` borrows) and what it writes (a single named
113+
data owner). See the explicit-dataflow rule in `src/AGENTS.md`.
109114

110115
## Value Blocks
111116

src/AGENTS.md

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,48 @@
11
# Source Tree
22

3-
- `src/input/` owns typed atmosphere, geometry, surface, spectroscopy, instrument, and reference-data input structures.
4-
- `src/forward_model/` owns optical-property preparation, radiative transfer, instrument-grid calculation, and implementation bindings.
3+
- `src/input/` owns typed atmosphere, geometry, surface, spectroscopy, instrument, and reference-data input structures, plus JSON, defaults, and validation.
4+
- `src/setup/` builds the named physics tables consumed by the hot path: atmosphere layers, line, CIA, aerosol, instrument, solar, phase, and O2 run tables.
5+
- `src/optics/` owns per-sample optical properties: layer depths, Rayleigh, CIA absorption, curved sun path, and source levels.
6+
- `src/rtm/` owns radiative transfer: controls, gauss angles, attenuation, phase basis, scattering orders, layer reflect/transmit, reflectance, and the `solve` entry point.
7+
- `src/spectrum/` owns spectral assembly: sampling table, line physics, solar lookup, radiance wavelengths/results, instrument averaging, and the `spectrum_run` driver.
8+
- `src/retrieval/` owns optimal-estimation algebra and its root entry point.
59
- `src/output/` owns diagnostic reports and spectrum serialization.
6-
- `src/common/` is shared support code only.
7-
- `src/validation/` owns validation-only CLIs that consume the typed O2 A baseline.
8-
- `src/forward_model/instrumentation/` owns narrow no-op-by-default facades for trace, telemetry, and sensitivity hooks. Retained sinks, capture scripts, and reports live under `scaffolding/`.
10+
- `src/cache/` owns retained, named memory owners (session, profile-line, radiance, solar-irradiance, spectrum, transport-worker, worker-pool). These are the borrowed write targets the hot path threads through.
11+
- `src/common/` is shared support code only: errors, hashing, math, units, memory, worker partition.
12+
- `src/assets/` owns embedded asset readers.
13+
- `src/validation/` owns validation-only code that consumes the typed O2 A baseline.
14+
- `src/instrumentation/` owns narrow no-op-by-default facades for trace, telemetry, and sensitivity hooks. Retained sinks, capture scripts, and reports live under `scaffolding/`.
915

1016
## Rules
1117

1218
- Inline `test` blocks under `src/` are not allowed. Add tests under `tests/unit/`, mirroring the source path.
1319
- Tests that need non-public symbols should use `src/internal.zig`; keep that access surface named after the current tree.
14-
- Prefer the public flow input -> RTM -> output. Do not move product wiring into `src/common/`.
20+
- Prefer the public flow input -> setup -> optics -> rtm -> spectrum -> output. Do not move product wiring into `src/common/`.
1521
- Comments explain why, not what. Keep comments near non-obvious DISAMAR semantics, unit conversions, sign conventions, ordering, and intentional divergences.
16-
- File I/O and text parsing belong in input, output, validation, scaffolding, CLI, or scripts, not in RTM routines.
22+
- File I/O and text parsing belong in input, output, validation, scaffolding, CLI, or scripts, not in optics, rtm, spectrum, or retrieval routines.
1723
- Every new input/config field must be consumed, rejected with a typed error, or explicitly documented as inert with focused test coverage.
24+
25+
## Explicit dataflow (hot folders)
26+
27+
Functions in the hot folders `src/optics`, `src/rtm`, `src/spectrum`, and
28+
`src/retrieval` must name what they read and write. Pass explicit scalars,
29+
slices, and named physics tables; borrow read-only data as `*const`; confine
30+
writes to a single named data owner. This keeps each function's dependencies
31+
visible in its signature instead of hidden inside a broad mutable object, which
32+
is what makes the hot path readable and property-testable.
33+
34+
This is enforced by `scripts/linting/check-explicit-dataflow-signatures.py`,
35+
which scans signatures and type declarations in those folders.
36+
37+
- Banned in signatures and as type names: `Scene`, `PreparedOpticalState`,
38+
`ProductStorage`, `Context`, `Workspace`, `Request`, `Cache`, `ComputeCache`,
39+
`Storage`, and any identifier ending in `Request` or `Workspace`. A
40+
god-object parameter hides what the function actually touches.
41+
- Allowed named data owners (the only broad-ish types permitted in hot-folder
42+
signatures): `SolarIrradianceMemory`, `ProfileLineValues`,
43+
`TransportWorkArrays`, `SpectrumSamplingTable`, `RadianceWavelengthList`.
44+
- The allowed list is the real governance lever. Keep these owners narrow; do
45+
not let one grow into a catch-all. Adding a name to the list (in the linter)
46+
is a deliberate decision, not a convenience.
47+
- Document each hot-path function's reads and writes in a `dataflow` section of
48+
its function map (see `STYLEGUIDE.md`).

0 commit comments

Comments
 (0)