Skip to content

Refactor explicit dataflow setup tables#82

Merged
bout3fiddy merged 115 commits into
mainfrom
codex/explicit-dataflow-refactor
Jun 14, 2026
Merged

Refactor explicit dataflow setup tables#82
bout3fiddy merged 115 commits into
mainfrom
codex/explicit-dataflow-refactor

Conversation

@bout3fiddy

@bout3fiddy bout3fiddy commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • add explicit-dataflow guardrail scaffolding for the active work packages
  • cut the active Zig graph over to WP2 setup tables, typed O2 case controls, asset readers, cache/profile-line memory, and instrumentation facades
  • keep struct memory-layout comments explicit, including namespace-only and trace facade structs

Verification

  • zig build check
  • zig build test-fast
  • uv run --no-project --python 3.14 python scripts/linting/check-zig-styleguide.py --format text src/internal.zig src/instrumentation/trace.zig
  • custom src struct scan for missing layout(64-bit) blocks
  • compiler layout probe for WP2 data structs and ?ztracy.ZoneCtx
  • prek run --all-files

Note

High Risk
Large-scale move of RTM/optics/spectrum code and a breaking Python API rename touch the core forward and retrieval path; benchmark retrieval skip logic also means OE coverage can be absent when native retrieval is still unsupported.

Overview
This PR restructures the Zig product around an explicit pipeline (inputsetupopticsrtmspectrumoutput / retrieval) instead of the old forward_model layout, with hot-path rules documented in src/AGENTS.md and STYLEGUIDE (dataflow sections, banned god-object parameter names).

Build and tests are realigned: instrumentation stubs move under src/instrumentation/, zig build drops the old validation-o2a step matrix in favor of test-unit / test-rtm / test-retained and C ABI gates, and benchmarks can skip OE when retrieval raises typed “unsupported” errors instead of failing the whole run.

Python renames the O2 A surface: O2AInputScene, reference_case()reference_scene(), RTM load_scene, OE scene= / scene_for_state, and related type renames (LineByLine, Optimisation). JSON parsing gains placeholder_float for omitted/null optional fields; SurfaceAlbedo is no longer in the public OE exports.

Docs, DISAMAR link targets, and regenerated benchmark/results.json follow the new paths and naming.

Reviewed by Cursor Bugbot for commit 91d8b0b. Bugbot is set up for automated code reviews on this repo. Configure here.

…factor

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.
@bout3fiddy bout3fiddy marked this pull request as ready for review June 14, 2026 08:51
Comment thread build.zig Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 307ed9f4cc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/root.zig
Comment thread src/input/validate.zig Outdated
Comment thread src/input/validate.zig Outdated
Comment thread src/output/atmospheric_budget.zig Outdated
Comment thread src/input/validate.zig Outdated
Comment thread benchmark/run_benchmark_fast.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bc5cb3255e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/root.zig Outdated
Comment thread src/api/c.zig
Comment thread src/api/c.zig
Comment thread src/root.zig Outdated
Comment thread src/retrieval/root.zig Outdated
Comment thread src/retrieval/root.zig Outdated
Comment thread src/cache/profile_line_memory.zig Outdated
Comment thread benchmark/run_benchmark.py

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 89407e5788

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/input/json.zig Outdated
Comment thread src/input/validate.zig Outdated
Comment thread build.zig
@bout3fiddy bout3fiddy force-pushed the codex/explicit-dataflow-refactor branch 2 times, most recently from 59c12ea to abe782f Compare June 14, 2026 18:19
Comment thread build.zig Outdated
@bout3fiddy bout3fiddy force-pushed the codex/explicit-dataflow-refactor branch 2 times, most recently from 0191dcd to cffbd37 Compare June 14, 2026 18:46

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit cffbd37. Configure here.

Comment thread src/api/c.zig Outdated
@bout3fiddy bout3fiddy force-pushed the codex/explicit-dataflow-refactor branch from cffbd37 to 91d8b0b Compare June 14, 2026 18:54
@bout3fiddy bout3fiddy merged commit 4b0c2f2 into main Jun 14, 2026
10 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

if isinstance(value, float) and math.isnan(value):
return "nan"

P1 Badge Emit native placeholders as parseable nulls

When Python-built scenes are sent through Scene.to_native_json_bytes(), the default altitude placeholders are math.nan, and this conversion writes them as the JSON string "nan". The native parser only normalizes bare NaN tokens and its placeholder fields are typed as ?f64, so normal scenes from o2a.reference_scene() or validation.o2a.case.build_o2a_case() fail during zds_prepare_o2a_json before the inert-placeholder validation can accept them; emit null (or leave bare NaN for the existing normalizer) instead of a string.


return min(start_count, max(1, min(2, native_worker_limit)))

P2 Badge Keep diagnosis batch workers at the native-supported count

Fresh evidence after the native rejection is that diagnose_retrieval() still calls this helper when batch_workers is omitted; with the default 30 starts on any machine where ZDISAMAR_WORKER_LIMIT/CPU count is at least 2, it returns 2. That value is passed through diagnosis_batch() to the C batch request, which now rejects batch_worker_count != 1, so a default Result.diagnose() fails before running the multi-start sweep; clamp this helper/default to 1 or expose a supported Python-level parallel path.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

while (source_interval_index > 0) {
source_interval_index -= 1;
const interval = intervals[source_interval_index];
const rtm_interval_index_1based: u32 = @intCast(intervals.len - source_interval_index);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve scene interval ids in the layer grid

When callers place scalar aerosol or the aerosol-pressure retrieval state in interval 1 or 3, the scene validates aerosol.interval_index_1based against the input interval ids, but this layer-grid fill renumbers intervals bottom-up with intervals.len - source_interval_index. fillSupportOpticsAtWavelength later matches aerosol support rows by these rewritten ids, so valid aerosol optical depth is deposited into the opposite interval instead of the requested pressure span. Preserve interval.index_1based here, or remap the aerosol table consistently, so enabled aerosol is not moved silently.

Useful? React with 👍 / 👎.

Comment on lines +278 to +280
const strong_state = line_physics.prepareStrongLineState(
tables.lines.strong_lines,
tables.lines.relaxation_matrix,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Filter diagnostic strong sidecars by isotope selection

When isotopes_sim excludes isotope 1, the forward profile-line path now disables the LISA strong-line sidecars, but this diagnostic builder still prepares sidecar state from the unfiltered tables.lines.strong_lines and then emits those rows. That makes o2_line_contributions report isotope-1 strong/line-mixing contributions for an isotope-2-only run, contradicting the spectrum and misleading validation diagnostics; apply the same isotope-one gate used by the profile-line cache before preparing these rows.

Useful? React with 👍 / 👎.

self._scene = copy.deepcopy(rtm_scene) if copy_scene else None
self._scene_fingerprint = payload
self._loaded_has_multi_layer_aerosol_profile = len(rtm_scene.aerosol.profile) > 1
self._solar_mu0 = rtm_scene.geometry.solar_mu0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reuse the floored solar cosine in Python scaling

For near-horizon solar angles, the native ABI now converts reflectance Jacobians back to radiance with the floored transport cosine, but this handle stores the raw cos(sza) and Spectrum.reflectance_jacobian() divides by that value. Fresh evidence after the native fix is that compactRadianceJacobian uses the floor while this saved solar_mu0 does not, so Python callers get reflectance Jacobians inflated by 0.05 / cos(sza) for accepted grazing geometries; store/expose the same floored cosine here (and when include_scene=True).

Useful? React with 👍 / 👎.

Comment on lines +1255 to +1257
if (!has_strong_lines) return @max(instrument.adaptive_points_per_fwhm, 1);
const min_divisions = @max(instrument.strong_line_min_divisions, 1);
const max_divisions = @max(instrument.strong_line_max_divisions, min_divisions);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject invalid adaptive-grid division controls

When native JSON or a typed Scene sets adaptive_reference_grid.points_per_fwhm, strong_line_min_divisions, or strong_line_max_divisions to 0 (or a max below min), validation still accepts the case and this hot path coerces the parsed values with @max(..., 1)/@max(max, min). That silently changes an experiment control and produces a support grid different from the requested one; reject zero or inconsistent adaptive-grid counts at the input boundary instead.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant