Skip to content

Finalized audit fixture of CFD crate - #721

Merged
marvin-hansen merged 16 commits into
deepcausality-rs:mainfrom
marvin-hansen:main
Aug 10, 2026
Merged

Finalized audit fixture of CFD crate#721
marvin-hansen merged 16 commits into
deepcausality-rs:mainfrom
marvin-hansen:main

Conversation

@marvin-hansen

@marvin-hansen marvin-hansen commented Jul 26, 2026

Copy link
Copy Markdown
Member

Describe your changes

Finalized audit fixture of CFD crate

Issue ticket number and link

Code checklist before requesting a review

  • I have signed the DCO?
  • All tests are passing when running make test?
  • No errors or security vulnerabilities are reported by make check?

For details on make, please see BUILD.md

Note: The CI runs all of the above and fixing things before they hit CI speeds
up the review and merge process. Thank you.


Summary by cubic

Finalizes the pre-certification audit for deep_causality_cfd: fixes ESKF/navigation correctness and error paths, versions the nav snapshot, reconciles docs with the shipped code, and adds full traceability. Also defaults CPU parallelism and refreshes Rust/Bazel deps; latest commit polishes the crate README.

  • Bug Fixes

    • ESKF/navigation: discretized process noise (Q_d = Q_c·dt), guarded scalar update (finite z, r ≥ 0, s > 0), covariance validated (finite, symmetric, non-negative diagonal), nominal body→nav quaternion carried/integrated and corrected on fixes; APIs return Result; Quaternion re-exported.
    • Error paths: ReentryNavEngine::predict stages run on locals and commit on success; NavFilter::predict returns Result and rejects bad dt/spectral densities; TrajectoryNav defers the optical take until after a GNSS attempt.
    • Snapshot/resume: nav section bumped to v2 (adds nominal attitude); v1 resumes with identity attitude to avoid mis-parse.
    • DEC/QTT: convective term marched in skew-symmetrized form; CompressibleEuler1d::new validates CFL in (0,1], γ > 1, finite dx; added nonzero-velocity convection test; removed stale Gates API.
  • Documentation & Traceability

    • Docs synced to code: projector eigenmodes (four zeroed), pressure-strip units and limits, dissipation peak vs endpoint, solver equation (in-stage projection, Δ_dR), blended-map preconditions, ambient body-force consumption, regime logging scope, fork semantics, and performance notes (CPU parallel now default). README updated and polished.
    • Traceability: added deep_causality_cfd/papers/ index; cited sources/units for load-bearing constants; cleaned leaked absolute paths; fixed stale/broken references; updated Rust crates (Cargo.lock) and Bazel modules (bazel_skylib, rules_rust), and refreshed vendored deps.

Written for commit 49935ff. Summary will update on new commits.

Review in cubic

…tness defects

The GNSS-denial navigation stack (NavFilter / ReentryNavEngine) carried three
independent defects the pre-certification audit flagged (AUDIT-REPORT §4b and §9
Phase 2 item 9), all in the estimation layer that decides drift through a comms
blackout and reacquisition afterward. The 17-state composition, the transition
matrix, and the Joseph covariance update were confirmed correct by the audit and
are byte-unchanged; the defects were around them.

- Process noise had no discretisation. `predict` added `Q` with no `dt`, so
  covariance grew with step count, not elapsed time, and the tuning was silently
  bound to one step size. Now `Q_d = Q_c·dt`: the supplied diagonal is a documented
  continuous-time spectral density (first-order, Groves 2013 §14.2.4). `Q_DIAG` is
  re-expressed as a spectral density (÷DT_FLIGHT); at the examples' fixed dt this
  reproduces the calibrated per-step Q bit-for-bit.

- The innovation covariance was divided by unguarded. `update_scalar` computed
  `s = h·P·hᵀ + r` and `k = P·hᵀ / s` with no positivity check and returned `()`,
  so `P[i][i]=0, r=0` wrote NaN into the whole state and covariance. It now returns
  `Result` and refuses a non-positive/non-finite `s` or a negative `r` atomically
  (every check precedes any mutation). `correct_position` snapshots and rolls back
  so its three per-axis folds are all-or-nothing.

- An attitude error was zeroed without ever being injected. `correct_position`
  credited an attitude-covariance reduction through the position↔attitude
  cross-covariance, then discarded the estimate — `ReentryNavEngine` carried no
  nominal attitude to apply it to. It now carries a nominal `Quaternion`, integrates
  the sensed body rate (a new `predict` argument), injects the estimated δψ on each
  fix, and only then resets — so the reset is legitimate. The nominal DCM rotates the
  body-frame specific force into the nav frame (C(q)·f_body) the −[f]× coupling
  reads, replacing the Tier-A C≈I assumption in the caller; nav_transition_matrix and
  propagate are unchanged.

Covariance construction and restoration now validate finiteness, symmetry (to √ε
relative tolerance), and a non-negative diagonal, making the degenerate-update path
unreachable rather than merely guarded.

Measured (corridor, weather, ins_gnss_blackout examples — all gates PASS): the
process-noise and guard changes are bit-identical at the fixed dt. The attitude
correction, now applied, folds a small δψ from the cross-covariance and shifts the
corridor's reacquisition error 0.2802 → 0.2804 m and its dead-reckoning variance
2.6711e1 → 2.6710e1 m² (≲0.07%, deterministic; every other figure bit-identical; the
weather shift is below display precision). corridor/output.txt is regenerated to
match. ins_gnss_blackout is a standalone P-controller model that uses neither filter
and is unaffected.

deep_causality_cfd tests: 895 passed, 0 failed. clippy -D warnings clean; no new

BREAKING CHANGE (in-crate only, publish = false): NavFilter::new and ::restore
return Result<Self, PhysicsError>; NavFilter::update_scalar returns
Result<(), PhysicsError>; ReentryNavEngine::predict and ::correct_position now
return Result; ReentryNavEngine::predict gains a sensed body angular-rate argument
and ::restore gains a nominal-attitude argument. Quaternion is re-exported from
deep_causality_cfd. The full-resume snapshot format gains four floats (the nominal
attitude).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
…update

An adversarial review of fix-navigation-filter-correctness (item 9) over its
finished diff found a residual gap in the same class the change closed:
NavFilter::update_scalar guarded the measurement variance `r` and the innovation
covariance `s` but not the measurement `z` itself. A non-finite `z` — a garbage
GNSS/optical fix, reachable through ReentryNavEngine::correct_position ← the
TrajectoryNav stage, which does not finiteness-check the fix cells — passed both
guards and wrote NaN into every state component (0·NaN = NaN, so even the
zero-gain ones), while the Joseph covariance update stayed finite. The corruption
was silent (returned Ok), invisible to the covariance/variance witness, and it
defeated correct_position's advertised all-or-nothing atomicity: no rejection
fired, so no rollback, and the nominal position/velocity/attitude were overwritten
with NaN.

update_scalar now rejects a non-finite `z` before any mutation, so the rejection
stays atomic and correct_position rolls back. Tests: a NaN/±∞ measurement is
refused and the filter left untouched; a non-finite fix through correct_position is
refused and the engine rolled back, and a later valid fix still folds.

Also corrects documentation the same review flagged: the Q_DIAG re-tune reproduces
the per-step Q to floating-point rounding, not "bit-for-bit" (the gyro-bias and
clock-drift blocks differ by ≤1 ULP, below any displayed digit); the predict and
attitude rustdoc no longer say a non-rotating vehicle's numbers are "unchanged" — a
fix injects a small δψ that shifts them. The snapshot round-trip test now evolves
the engine to a non-identity attitude so it bites on a pack/unpack ordering
regression of the four attitude floats.

deep_causality_cfd tests: 897 passed, 0 failed. clippy -D warnings clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
…c, archive fix-navigation-filter-correctness

Records fix-navigation-filter-correctness (item 9, the ESKF correctness defects) as
resolved and closes Phase 2 of the deep_causality_cfd pre-certification audit.

- AUDIT-REPORT.md: item 9 marked resolved at every touchpoint (§4b, §6 rank 15, §9
  item 9 and the Phase-2 header, §10). Phase 2 is now complete — all four Phase-2
  changes and all four certification blockers landed; Module 15 (Navigation / ESKF)
  moves not-ready → needs-work, leaving 16 as the sole not-ready module. Adds the
  item-9 remediation block recording what the adversarial pass over the finished
  diff caught: a correctness gap (the non-finite-z NaN path, fixed in the sibling
  commit) plus a cluster of documentation/spec overclaims, all mine — the same "not
  clean" lesson the three prior Phase-2 changes recorded — and one info-level
  verification gap deferred (the attitude-injection sign/axis is unexercised by the
  point-mass examples; full attitude observability is a Non-Goal).
- Synced the new eskf-filter-correctness capability into openspec/specs/ with a
  written Purpose. Its four requirements state the filter's contract: a discretised
  process noise, a guarded atomic update, a validated covariance, and a closed
  error-state lifecycle. The covariance requirement is scoped to the necessary
  conditions the code checks, with the update guard named as the operational PSD
  backstop (a construction-time LDLᵀ test would wrongly reject a Joseph-form
  covariance carrying a round-off-negative eigenvalue).
- Corrected the change's own artifacts against the tree before archiving:
  ins_gnss_blackout is a standalone model, not a filter call site; the Q re-tune is
  bit-exact bar ≤1 ULP on two blocks; validation narrows rather than makes the
  degenerate path "unreachable"; weather drift is unchanged at display precision,
  not at f64.
- Archived to openspec/changes/archive/2026-07-24-fix-navigation-filter-correctness/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
… CFD audit change

Folds Phase 3 (documentation truth-up, AUDIT-REPORT items 16-22) and Phase 4
(traceability, items 23-24) into one proposed change that closes out the
deep_causality_cfd pre-certification audit. Neither phase gates correctness — the
numerics are confirmed right against every closed-form reference — but both are the
audit's largest surviving themes and are what an engineer reads before trusting the
crate.

Structured as the two prior audit meta-changes were: two new cross-cutting
capabilities own the discipline rather than sprawling prose edits through dozens of
behavioural specs (the pattern Phase 1 set with verification-gate-integrity).

- documentation-code-parity (7 requirements): a kernel docstring names the operator
  the code marches (the DEC rate kernel's docs say −i_u(du♭) where it marches the
  skew-symmetrised ½[G_ω u − G*_ω u]); a comment does not contradict the code beneath
  it (the two projection.rs spectral comments, the mod.rs Chorin-vs-in-stage
  contradiction); a "by construction" claim names its check or is marked intent
  (~86 ACTION-LIST doc-overclaim rows); every shipped capability is documented where
  a user looks; a convergence claim states its order and regime (the QTT Taylor-Green
  "clean 2nd-order"); and no dead duplicate gate API ships (Gates).
- constant-and-test-traceability (2 requirements): every load-bearing constant carries
  a source, units, and a papers/ entry (SMOOTH_CELLS, the park2t ETA, the Mach-1.05
  floor, the Angot/Bruneau-Fabrie penalization reference); a load-bearing test
  references an independent truth, not the code's own prior output (drive the shipped
  QTT rate_pair convection path with u,v≠0; route the TG harness off its gradient_*
  re-assembly).

Reconciled against the tree before writing, per the audit's own recurring lesson:
- Items 19 (RAM-C framing), 20 (lid-cavity 65²-default row), and the cylinder ETA
  re-derivation (23) are already delivered by Phases 1-2 — excluded from task scope,
  captured in the spec with a regression scenario so they cannot silently rot, not
  re-done.
- The audit's "87 doc-overclaims" and "39 doc-gaps" are category estimates (86
  actionable rows / 91 raw occurrences; 39 is the doc-gap total, a mixed bag). The
  change works the catalogue and records the count it closes, not a round number.
- Two golden-rule deletion sensitivities are flagged for owner decision, not taken:
  retiring Gates (item 22) and the two orphan PDFs mittal2005/mohamed2016 (item 23).
  The change lands only the non-deleting corrections unless directed otherwise.

Proposed only — no implementation, no marched number moves. Design mandates the same
adversarial refute-by-default pass over the finished diff that every Phase-2 change
needed, since a truth-up change is the most exposed to its own overclaims.

openspec validate reconcile-cfd-docs-and-traceability --strict: valid (9 requirement
deltas).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
…etire Gates

Implements reconcile-cfd-docs-and-traceability, the final change of the
pre-certification audit: Phase 3 (documentation truth-up, items 16-22) and
Phase 4 (traceability, items 23-24). No marcher, kernel, or gate bound is
touched, and no example figure moves; the plasma_blackout_corridor example
reproduces its committed output.txt exactly.

Documentation reconciled against the code that ships:

- The DEC rate kernel's public docs described the un-symmetrised convective
  operator -i_u(du) while the code marches the skew-symmetrised
  conv' = 1/2[G_w u - G*_w u]. Corrected at every site, and verified that all
  four assembly paths (fused and generic, projected and unprojected) march the
  skew form, so the raw gather is neither marched nor exposed.
- The DEC solver's module prose described a first-order Chorin split. The code
  projects inside each RK4 stage with no splitting error, as step.rs already
  stated. The governing equation now also writes the viscous term with the same
  Delta_dR the solver evaluates, instead of mixing symbols.
- Two spectral-projector comments named the compact 5-point eigenvalue and the
  wrong sign; both now describe the consistent -sin^2(2pik/N)/dx^2 the code
  applies.
- CfdFlow::qtt_march does not exist. Six documentation sites named it; all now
  say CfdFlow::march.
- Crate README: chi^2*L is storage, not runtime (item 10 measured runtime rising
  far faster at flat bond); the Knudsen number classifies and logs, with no slip,
  transitional, or free-molecular closure implemented; RegimeSwitch and
  aero_gravity_ratio are public API with no call site, so the engine does not
  switch integrators; regime() returns seven fields, not four; the corridor
  transcript now matches output.txt byte for byte.

Item 21 is answered with a measurement rather than an assertion. The Taylor-Green
ladder holds dt fixed, so it measures spatial order, and the first-order Euler
error is a floor of opposite sign. The signed error runs +9.8e-4, +2.4e-4,
+5.3e-5, +5.9e-6, -5.9e-6, -8.8e-6 for N = 8..256: the two contributions cancel
near N = 64-128, so the N = 64 order of 3.16 is a cancellation artifact and the
order collapses to 0.02 by N = 128. The maximum usable ladder length is therefore
max_level = 5, the committed default. Recorded openly: at the documented
max_level 7 the harness fails its own order gate. Fixing that needs a two-sided
order gate or dt refined as dt ~ dx^2; both are code changes and are not taken
here.

Gates is retired (item 22, owner decision). It was a parallel gate-reporting API
that no shipped program constructed; Gates::new appeared only in its own unit
test, while every self-verifying program uses GateSeq or Verdict. Removed the
type, its tests, and its wiring. This fixes a documentation overclaim by
correcting the code rather than weakening the prose: Gates held the only five
println! in src/, which made the README's "the DSL never exits or prints" false.
src/ now contains zero println!, eprintln!, panic!, and process::exit, so the
claim is true as written. The type was in-crate only (publish = false).

Traceability:

- SMOOTH_CELLS, the qtt_park2t_blackout ETA, and the Mach-1.05 shock floor now
  state their source, units, and why the value is what it is. Each is recorded
  as a numerical or modelling parameter with no external source, which is the
  honest description; SMOOTH_CELLS carries its 6.1x drag sensitivity.
- Added papers/README.md, indexing every PDF to its citing code. The two PDFs
  carried uncited were read, confirmed on topic, and cited: Mohamed, Hirani &
  Samtaney (2016) at the DEC solver, Mittal & Iaccarino (2005) at the immersed
  body. References cited in code whose PDF is absent are listed as such.
- A test now drives the shipped QTT convection path rate_pair with u,v != 0
  against a hand-derived reference, closing the gap where the only tests passed
  u = v = 0 and the solver test's convection was annihilated by the projection.
  It bites: flipping the shipped convection sign fails it at max_err = 0.999
  against a 3e-3 bound. The Taylor-Green harness's convection check now runs
  through rate_pair instead of a gradient_x/gradient_y re-assembly, so it gates
  the shipped operator rather than a copy; its reported error is unchanged at
  3.207e-3.

The adversarial pass over the finished diff found four defects, all mine, all
fixed, and they are recorded in tasks.md:

- I concluded the temporal floor "is not observed" and shipped that into a
  docstring and two READMEs. It is false. The confirming N = 128 run had timed
  out and I wrote the conclusion without it, reading a cancellation artifact as
  continued convergence. Re-derived in closed form and corrected.
- I wrote a year, venue, volume, and page range for the Kazeev-Khoromskij
  reference from recall; this repository records only author and title. Reduced
  to what is verifiable, with the gap named in papers/README.md.
- Row 16.9 was recorded as closed when only half of it was done.
- The catalogue count contradicted itself across two tasks. Recounted and
  enumerated by ref.

Honest tally on the catalogue: 22 of 125 doc-overclaim and doc-gap rows closed
here, 9 confirmed already closed by Phases 1-2, and 94 left open and not claimed.
The remaining rows are mostly single-site docstrings; a subset asks for code
changes outside this change's scope. Item 18 needed no work: the README already
documented all four capabilities, and the earlier report that it did not came
from a malformed grep, which is the audit's own lesson about negatives resting
on an unstated search.

bazel test //...: 1153/1153 pass. cargo test -p deep_causality_cfd --release:
895 passed, 0 failed. clippy --all-targets --all-features -D warnings: clean.
No new rustdoc warning. openspec validate --strict: valid.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
… constants, retire Gates

Implements and archives reconcile-cfd-docs-and-traceability, completing Phase 3
(documentation truth-up, items 16-22) and Phase 4 (traceability, items 23-24) of
the pre-certification audit. Items 17 and 19-23 are closed in full, item 24 bar
its broadest sweep, and items 16 and 18 entirely.

The catalogue is fully accounted for: 125 of 125 doc-overclaim and doc-gap rows,
116 closed here and 9 already closed by Phases 1-2, with 0 remaining. Each closed
row is listed by ref in the change's tasks.md, so the count is recomputable from
ACTION-LIST.md rather than asserted. The other 165 raw findings (tautology-circular,
physics-math, magic-number) were closed earlier as consolidated Phase-1/2 items and
are not cleared row-by-row; §6 now says so explicitly.

Prose reconciled against the code that ships. The recurring shapes:

- Docs naming an operator the code does not march. The DEC rate kernel described
  the un-symmetrised -i_u(du) while all four assembly paths march the
  skew-symmetrised 1/2[G_w u - G*_w u]; the module doc described a first-order
  Chorin split where the code projects inside each RK4 stage; two spectral-projector
  comments gave the compact 5-point eigenvalue and the wrong sign.
- Docs naming an API that does not exist. CfdFlow::qtt_march appeared at six sites;
  the method is CfdFlow::march.
- Docs naming a wiring that was never done. RegimeSwitch and aero_gravity_ratio have
  no call site, so the README's claim that the navigation engine switches integrators
  was false. Ambient::set_body_force is read by no marcher. The event-fork path does
  not thread the audit sink.
- Units carried in a name. strip_pressure_force returns an undirected pressure volume
  integral in Pa*m^3, not a force; only its ratio through preserved_drag_fraction is
  meaningful. relax_length is a fraction of the sampled extent, not a length.
  BodyForceZone's cochain is an acceleration line integral.
- Claims stronger than the code. A fork shares the marched tensor state in O(1) but
  the coupled field clone is O(cells); a leg boundary re-seeds the marched fluid
  layer; SolenoidalField's type-state has two documented escape hatches; the
  Taylor-Green ladder measures spatial order only.

Gates is retired (item 22, owner decision). It was a parallel gate-reporting API no
shipped program constructed; Gates::new appeared only in its own unit test, while
every self-verifying program uses GateSeq or Verdict. Removing it fixed a
documentation overclaim by correcting the code rather than weakening the prose: it
held the only five println! in src/, which made the README's "the DSL never exits or
prints" false. src/ now contains zero println!, eprintln!, panic! and process::exit,
so the claim is true as written. The type was in-crate only (publish = false).

Code changes, kept small and each verified:

- CompressibleEuler1d::new validates its numerical envelope (dx, gamma, cfl),
  matching the pattern the shock-fitting and QTT constructors already use, with four
  tests including one asserting the shipped configuration is still accepted.
- A test drives the shipped QTT convection path rate_pair with u,v != 0 against a
  hand-derived reference, closing the gap where the only tests passed u = v = 0 and
  the solver test's convection was annihilated by the projection. It bites: flipping
  the shipped convection sign fails it at max_err = 0.999 against a 3e-3 bound.
- The Taylor-Green harness's convection check runs through rate_pair instead of a
  gradient_x/gradient_y re-assembly, so it gates the shipped operator rather than a
  copy. Its reported error is unchanged at 3.207e-3.
- The corridor example sums pause.rebuilds() across its four legs instead of counting
  log substrings. The example reproduces its committed output.txt identically.

Traceability. SMOOTH_CELLS, the qtt_park2t_blackout ETA and the Mach-1.05 shock floor
now state source, units and the reason for the value, each recorded honestly as a
numerical or modelling parameter with no external source. Added papers/README.md
indexing every PDF to its citing code: the two PDFs carried uncited were read,
confirmed on topic and cited (Mohamed, Hirani & Samtaney 2016 at the DEC solver;
Mittal & Iaccarino 2005 at the immersed body). References cited in code whose PDF is
absent are listed as absent.

One live defect surfaced and deliberately not fixed. Item 21 asked for the
Taylor-Green ladder's temporal floor and maximum usable length. Deriving it in closed
form shows the fixed-dt Euler error is opposite in sign to the spatial error: the
signed error runs +9.8e-4, +2.4e-4, +5.3e-5, +5.9e-6, -5.9e-6, -8.8e-6 for N = 8..256,
so the two cancel near N = 64-128, the N=64 order of 3.16 is a cancellation artifact,
and by N=128 the order collapses to 0.02. The harness therefore FAILS at its own
documented max_level 7. max_level = 5 is the maximum usable length and is now
documented. Fixing the extended ladder needs a two-sided order gate or dt ~ dx^2, both
behaviour changes, recorded and deferred. A second finding is recorded and not fixed:
the crate's public API leaks workspace types it does not re-export.

Artifacts. Nine committed baselines and outputs were stale against their programs and
are regenerated from actual runs (qtt_sod, qtt_blunt_body_2d, qtt_reentry_3d,
qtt_park2t_blackout, mms_taylor_green, dec_taylor_green_re1600, and three study or
example outputs). All gates PASS with zero FAILs. qtt_cylinder_verification's baseline
is left as the superseded L = 5 capture and labelled as such, because regenerating it
needs the 4-9 hour offline acceptance run.

AUDIT-REPORT.md records Phases 1-4 complete, with §6 rewritten. Only module 6
(Docs-vs-code parity) moves to ready, because it is the one module whose finding set
was closed row-by-row with a recomputable count. The other fifteen keep their as-found
readiness and the report states why: re-rating them needs a re-audit of the three
non-documentation axes, which no one has run. Module 13's critical count is corrected
1 -> 0 (B-3 was resolved in Phase 1). Module 16 stays not-ready on the offline drag
gate.

Method, recorded because it is the lesson rather than a footnote. The adversarial pass
over the finished diff found four defects, all mine: a conclusion about the temporal
floor published without its confirming measurement (the N=128 run had timed out); a
Kazeev-Khoromskij citation whose year, venue and pages I supplied from recall when the
repository records only author and title; a row marked closed when half of it was done;
and a catalogue count that contradicted itself across two tasks. Separately, the count
was wrong three times before it was right, and one batch of two rows was dropped from
the work assignments entirely. None of that was caught by review. All of it was caught
by recomputing the count against the catalogue, which is the argument for keeping the
tally recomputable.

bazel test //...: 1153/1153 pass. cargo test -p deep_causality_cfd --release: 900
passed, 0 failed. deep_causality_physics: 1742 passed, 0 failed. clippy --all-targets
--all-features -D warnings: clean across cfd, physics and avionics_examples. Rustdoc
warnings 12 -> 9. plasma_blackout_corridor reproduces its committed output exactly.
openspec validate --strict: valid; archived as
2026-07-26-reconcile-cfd-docs-and-traceability with both capability specs synced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
@marvin-hansen marvin-hansen self-assigned this Jul 26, 2026
@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.86364% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.02%. Comparing base (b70826c) to head (49935ff).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...lity_cfd/src/types/flow/corridor/trajectory_nav.rs 87.50% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main     #721    +/-   ##
========================================
  Coverage   97.02%   97.02%            
========================================
  Files        1283     1282     -1     
  Lines       74971    75088   +117     
========================================
+ Hits        72738    72857   +119     
+ Misses       2233     2231     -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

13 issues found across 182 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="openspec/audits/cfd_audit/ACTION-LIST.md">

<violation number="1" location="openspec/audits/cfd_audit/ACTION-LIST.md:203">
P2: Suggested relative path `../../../papers` in the action text is wrong when resolved from `deep_causality_cfd/README.md` (the file being edited). `../../../papers` walks 3 levels up from `deep_causality_cfd/`, putting it outside the repository. The correct relative path to reach `<repo_root>/papers/` from the README is `../papers`.</violation>
</file>

<file name="deep_causality_cfd/src/types/flow/corridor/trajectory_nav.rs">

<violation number="1" location="deep_causality_cfd/src/types/flow/corridor/trajectory_nav.rs:98">
P2: A failed predict with a biased IMU leaves only attitude advanced, so retrying the step double-integrates gyro rotation. Restore a pre-predict engine snapshot on this error path, or make `ReentryNavEngine::predict` transactional.</violation>
</file>

<file name="deep_causality_cfd/src/navigation/reentry_nav.rs">

<violation number="1" location="deep_causality_cfd/src/navigation/reentry_nav.rs:108">
P1: A rotated vehicle now propagates its trajectory with body-frame acceleration while the filter uses nav-frame acceleration. Derive `f_nav` before `ks_strang_step` and use it for both nominal kick and filter, or keep this API Cartesian end-to-end.</violation>

<violation number="2" location="deep_causality_cfd/src/navigation/reentry_nav.rs:109">
P1: Nonzero-rate runs now have an attitude nominal that the ESKF does not linearize around, producing incorrect attitude/gyro-bias cross-covariances and fix corrections. Extend filter propagation with nominal attitude and angular rate, or retain the identity-attitude model.</violation>

<violation number="3" location="deep_causality_cfd/src/navigation/reentry_nav.rs:157">
P2: After a nonzero `δψ` injection, covariance remains expressed in the pre-injection attitude-error coordinates, so later gains can become inconsistent. Apply the ESKF attitude-reset Jacobian to covariance before zeroing the attitude error.</violation>
</file>

<file name="openspec/changes/archive/2026-07-26-reconcile-cfd-docs-and-traceability/specs/constant-and-test-traceability/spec.md">

<violation number="1" location="openspec/changes/archive/2026-07-26-reconcile-cfd-docs-and-traceability/specs/constant-and-test-traceability/spec.md:10">
P3: Line ref for SMOOTH_CELLS in cylinder config is off by ~10 lines. `SMOOTH_CELLS: f64 = 2.0` is at line 54, not 44. Doc comment starts at line 47.</violation>

<violation number="2" location="openspec/changes/archive/2026-07-26-reconcile-cfd-docs-and-traceability/specs/constant-and-test-traceability/spec.md:12">
P3: Line ref for SMOOTH_CELLS in park2t config is off. SMOOTH_CELLS is at line 45, not 37. Doc comment starts at line 40.</violation>

<violation number="3" location="openspec/changes/archive/2026-07-26-reconcile-cfd-docs-and-traceability/specs/constant-and-test-traceability/spec.md:13">
P3: Line ref for ETA in park2t config is off by 4 lines. ETA = 0.016 is at line 35, not 31. Line 31 is a doc comment continuation.</violation>

<violation number="4" location="openspec/changes/archive/2026-07-26-reconcile-cfd-docs-and-traceability/specs/constant-and-test-traceability/spec.md:16">
P3: Line ref for the shock-floor explanation in compressible_march_run.rs is wrong. The 1.05-buffer comment is at lines 330-334, not 326-327. Lines 326-327 are computational (`let altitude = ...`, `let row = ...`).</violation>

<violation number="5" location="openspec/changes/archive/2026-07-26-reconcile-cfd-docs-and-traceability/specs/constant-and-test-traceability/spec.md:17">
P3: Line ref for the Angot citation in print_utils.rs is off. The Angot/Bruneau/Fabrie citation is at line 136, not 122. Line 122 prints DEC_CD_REF cross-reference.</violation>
</file>

<file name="deep_causality_cfd/src/navigation/eskf.rs">

<violation number="1" location="deep_causality_cfd/src/navigation/eskf.rs:159">
P3: The constructor docs say zero variances are refused, but the implementation and tests intentionally accept zero at the PSD boundary. Update this sentence so callers do not avoid valid deterministic initial-state covariances.</violation>

<violation number="2" location="deep_causality_cfd/src/navigation/eskf.rs:163">
P1: Malformed snapshot covariances can still be restored and used by the filter. Symmetry plus non-negative variances is not PSD; add a PSD check (for example, a tolerance-aware Cholesky/LDLᵀ factorization) before accepting `cov`.</violation>

<violation number="3" location="deep_causality_cfd/src/navigation/eskf.rs:194">
P2: Long predict-only runs can save a covariance that the new `restore` rejects because this path reintroduces floating-point asymmetry. Re-symmetrizing after predict keeps snapshot/resume compatible with the new restore invariant.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread deep_causality_cfd/src/types/flow/state_snapshot.rs
// The accelerometer senses the non-gravitational (aero) specific force in the *body* frame;
// rotate it into the nav frame via the nominal DCM before the filter's error-dynamics use it.
let f_nav = mat3_vec(&self.attitude.to_rotation_matrix(), aero_accel);
self.filter.predict(dt, f_nav, process_noise);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Nonzero-rate runs now have an attitude nominal that the ESKF does not linearize around, producing incorrect attitude/gyro-bias cross-covariances and fix corrections. Extend filter propagation with nominal attitude and angular rate, or retain the identity-attitude model.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/src/navigation/reentry_nav.rs, line 109:

<comment>Nonzero-rate runs now have an attitude nominal that the ESKF does not linearize around, producing incorrect attitude/gyro-bias cross-covariances and fix corrections. Extend filter propagation with nominal attitude and angular rate, or retain the identity-attitude model.</comment>

<file context>
@@ -43,37 +55,58 @@ pub struct ReentryNavEngine<R: RealField + FromPrimitive> {
+        // The accelerometer senses the non-gravitational (aero) specific force in the *body* frame;
+        // rotate it into the nav frame via the nominal DCM before the filter's error-dynamics use it.
+        let f_nav = mat3_vec(&self.attitude.to_rotation_matrix(), aero_accel);
+        self.filter.predict(dt, f_nav, process_noise);
         // Carried clock: dτ/dt − 1 at the current geometry, integrated on proper time (s ≠ τ).
         let radius = norm(r1);
</file context>

self.filter.predict(dt, aero_accel, process_noise);
// The accelerometer senses the non-gravitational (aero) specific force in the *body* frame;
// rotate it into the nav frame via the nominal DCM before the filter's error-dynamics use it.
let f_nav = mat3_vec(&self.attitude.to_rotation_matrix(), aero_accel);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: A rotated vehicle now propagates its trajectory with body-frame acceleration while the filter uses nav-frame acceleration. Derive f_nav before ks_strang_step and use it for both nominal kick and filter, or keep this API Cartesian end-to-end.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/src/navigation/reentry_nav.rs, line 108:

<comment>A rotated vehicle now propagates its trajectory with body-frame acceleration while the filter uses nav-frame acceleration. Derive `f_nav` before `ks_strang_step` and use it for both nominal kick and filter, or keep this API Cartesian end-to-end.</comment>

<file context>
@@ -43,37 +55,58 @@ pub struct ReentryNavEngine<R: RealField + FromPrimitive> {
-        self.filter.predict(dt, aero_accel, process_noise);
+        // The accelerometer senses the non-gravitational (aero) specific force in the *body* frame;
+        // rotate it into the nav frame via the nominal DCM before the filter's error-dynamics use it.
+        let f_nav = mat3_vec(&self.attitude.to_rotation_matrix(), aero_accel);
+        self.filter.predict(dt, f_nav, process_noise);
         // Carried clock: dτ/dt − 1 at the current geometry, integrated on proper time (s ≠ τ).
</file context>

Comment thread deep_causality_cfd/src/navigation/eskf.rs
/// makes the degenerate measurement-update path reachable, so it is refused at the entry point.
pub fn new(state: InsErrorState<R>, cov_diag: [R; NAV_STATES]) -> Result<Self, PhysicsError> {
let cov = diag(&cov_diag);
validate_covariance(&cov)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Malformed snapshot covariances can still be restored and used by the filter. Symmetry plus non-negative variances is not PSD; add a PSD check (for example, a tolerance-aware Cholesky/LDLᵀ factorization) before accepting cov.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/src/navigation/eskf.rs, line 163:

<comment>Malformed snapshot covariances can still be restored and used by the filter. Symmetry plus non-negative variances is not PSD; add a PSD check (for example, a tolerance-aware Cholesky/LDLᵀ factorization) before accepting `cov`.</comment>

<file context>
@@ -88,36 +148,125 @@ pub struct NavFilter<R: RealField> {
+    /// makes the degenerate measurement-update path reachable, so it is refused at the entry point.
+    pub fn new(state: InsErrorState<R>, cov_diag: [R; NAV_STATES]) -> Result<Self, PhysicsError> {
+        let cov = diag(&cov_diag);
+        validate_covariance(&cov)?;
+        Ok(Self { state, cov })
     }
</file context>


The mask-smoothing width `SMOOTH_CELLS = 2.0` moves the reported immersed-cylinder `C_d` by 6.1×
(`AUDIT-REPORT.md` §4b) and carries only "Mask smoothing width in cells." at both definitions
(`verification/qtt_cylinder_verification/config.rs:44`, `qtt_park2t_blackout/config.rs:37`). The

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: Line ref for SMOOTH_CELLS in park2t config is off. SMOOTH_CELLS is at line 45, not 37. Doc comment starts at line 40.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At openspec/changes/archive/2026-07-26-reconcile-cfd-docs-and-traceability/specs/constant-and-test-traceability/spec.md, line 12:

<comment>Line ref for SMOOTH_CELLS in park2t config is off. SMOOTH_CELLS is at line 45, not 37. Doc comment starts at line 40.</comment>

<file context>
@@ -0,0 +1,61 @@
+
+The mask-smoothing width `SMOOTH_CELLS = 2.0` moves the reported immersed-cylinder `C_d` by 6.1×
+(`AUDIT-REPORT.md` §4b) and carries only "Mask smoothing width in cells." at both definitions
+(`verification/qtt_cylinder_verification/config.rs:44`, `qtt_park2t_blackout/config.rs:37`). The
+`qtt_park2t_blackout` `ETA = 0.016` (`config.rs:31`) carries no source, while the cylinder site
+(`qtt_cylinder_verification/config.rs:32-38`) already carries a wall-error-target derivation from
</file context>

Comment on lines +159 to +160
/// checked here (see [`validate_covariance`]). Admitting a zero or negative variance here is what
/// makes the degenerate measurement-update path reachable, so it is refused at the entry point.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The constructor docs say zero variances are refused, but the implementation and tests intentionally accept zero at the PSD boundary. Update this sentence so callers do not avoid valid deterministic initial-state covariances.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/src/navigation/eskf.rs, line 159:

<comment>The constructor docs say zero variances are refused, but the implementation and tests intentionally accept zero at the PSD boundary. Update this sentence so callers do not avoid valid deterministic initial-state covariances.</comment>

<file context>
@@ -88,36 +148,125 @@ pub struct NavFilter<R: RealField> {
+    /// # Errors
+    /// Rejects a `cov_diag` that is not a covariance diagonal: a non-finite entry, or a negative
+    /// variance. A diagonal is symmetric by construction, so only finiteness and non-negativity are
+    /// checked here (see [`validate_covariance`]). Admitting a zero or negative variance here is what
+    /// makes the degenerate measurement-update path reachable, so it is refused at the entry point.
+    pub fn new(state: InsErrorState<R>, cov_diag: [R; NAV_STATES]) -> Result<Self, PhysicsError> {
</file context>
Suggested change
/// checked here (see [`validate_covariance`]). Admitting a zero or negative variance here is what
/// makes the degenerate measurement-update path reachable, so it is refused at the entry point.
/// checked here (see [`validate_covariance`]). Zero is allowed at the PSD boundary; a negative
/// variance is refused at the entry point.

Comment thread openspec/specs/documentation-code-parity/spec.md Outdated
Comment thread examples/avionics_examples/cfd/plasma_blackout/corridor/model.rs Outdated
Comment thread openspec/audits/cfd_audit/AUDIT-REPORT.md Outdated
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
@socket-security

socket-security Bot commented Aug 10, 2026

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

21 issues found across 1707 files

Not reviewed (too large): thirdparty/crates/rustix-1.1.4/BUILD.bazel (~84 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="deep_causality_cfd/src/solvers/dec/boundary/body_force_zone.rs">

<violation number="1" location="deep_causality_cfd/src/solvers/dec/boundary/body_force_zone.rs:23">
P3: The new doc comment references `DecNsRate` as plain backticked code (`see `DecNsRate``) rather than an intra-doc link, so it renders as code text and won't become a clickable cross-reference in the generated docs. The rest of the crate links it as [`DecNsRate`]; consider matching that so the audit note actually cross-links to the rate type it describes.</violation>
</file>

<file name="openspec/changes/archive/2026-07-24-fix-navigation-filter-correctness/specs/eskf-filter-correctness/spec.md">

<violation number="1" location="openspec/changes/archive/2026-07-24-fix-navigation-filter-correctness/specs/eskf-filter-correctness/spec.md:75">
P2: The scenario 'A non-PSD covariance is refused at construction' contradicts the revised requirement just above it. Since construction deliberately skips the full PSD/LDLᵀ check and only rejects necessary-condition violations, a symmetric non-PSD matrix with an all-positive diagonal (e.g. a round-off-negative eigenvalue from off-diagonal entries, like [[1,2],[2,1]]) still passes construction — so the title overpromises a rejection the spec and design (D3) both explicitly disclaim. Rename the scenario (and its WHEN) to what actually holds, e.g. 'A covariance violating a necessary condition is refused at construction', so a test author doesn't implement or expect a full-PSD rejection that won't occur.</violation>
</file>

<file name="deep_causality_cfd/studies/srp_momentum_jet/README.md">

<violation number="1" location="deep_causality_cfd/studies/srp_momentum_jet/README.md:57">
P3: This change retracts the cap-32 'compression is innocent' claim (compression is now 'unmeasured', no cap-32 run committed), but the sibling file `deep_causality_cfd/studies/README.md` (line 66) still asserts the exact disavowed result verbatim. The two READMEs in the same directory now contradict each other on whether a cap 24→32 sweep was run; update the summary row to match this retraction (e.g. 'compression unmeasured; cap-32 companion not run').</violation>
</file>

<file name="deep_causality_cfd/studies/compressible_carrier_timing/output.txt">

<violation number="1" location="deep_causality_cfd/studies/compressible_carrier_timing/output.txt:22">
P2: The freshly recorded reference output now measures the recommended config at 0.248 s/step (49.6 s corridor) and the 3-D shell at 3049 s, but README.md and studies/README.md still encode the previous run (0.175 s/step, 35 s corridor, 17x margin, 3-D 2161 s). This repo treats study output as gated evidence that must not silently change, so two authoritative sources now disagree on the recommended configuration's numbers; update both READMEs to match.</violation>
</file>

<file name="deep_causality_cfd/Cargo.toml">

<violation number="1" location="deep_causality_cfd/Cargo.toml:52">
P3: The newly added comment sentence `On in the \`default\` set above;` doesn't read clearly — it looks like the intended wording was something like "It is on in the `default` set above" or "On by default (it sits in the `default` set above)". Since this comment is the crate's documentation of how to select serial vs. parallel builds, the broken sentence makes the guidance harder to follow. Consider rewording, e.g. "It is on in the `default` set above; build with ..."</violation>
</file>

<file name="deep_causality_cfd/src/solvers/dec/uncertain_inflow/uncertain_boundary_source.rs">

<violation number="1" location="deep_causality_cfd/src/solvers/dec/uncertain_inflow/uncertain_boundary_source.rs:147">
P3: The rewording of this comment left a duplicated line: the newly added `// independent randomized-QMC realization; default is the MC mean.` is immediately followed by the pre-existing `// each step is an independent randomized-QMC realization; default is the MC mean.`, which says the same thing twice. Drop the redundant trailing line so the comment reads once.</violation>
</file>

<file name="examples/avionics_examples/src/shared/constants.rs">

<violation number="1" location="examples/avionics_examples/src/shared/constants.rs:194">
P3: The rewritten Q_DIAG doc claims that re-expressing the process noise as a continuous-time spectral density leaves "the filter's behaviour at DT_FLIGHT unchanged **at every displayed figure**", but the committed outputs in this same PR show the nav figures did change. The corridor `output.txt` diffs `position variance = 2.6711e1 m^2` → `2.6710e1 m^2` on the peak leg and `nav error vs truth = 0.2802 m` → `0.2804 m` on reacquisition, and the weather table's `drift_mean`/`drift_sd` values also all moved. The doc itself concedes the gyro-bias/clock-drift blocks (`1e-14`) only round-trip to ≤1 ULP, which is enough to perturb the filter over the couple-of-hundred-step descent into the displayed 4th decimal. So the "unchanged at every displayed figure" assertion is not borne out by the artifacts. Consider softening the claim (e.g. "no observable effect on the displayed figures at the stated precision") or noting the small drift variables' ULP differences do surface in the published numbers, so the doc and the committed outputs are consistent.</violation>
</file>

<file name="thirdparty/crates/fastrand-2.5.0/src/global_rng.rs">

<violation number="1" location="thirdparty/crates/fastrand-2.5.0/src/global_rng.rs:88">
P3: The doc comment now says a single 'range' while listing two disjoint ranges (a-z and A-Z, or 0-9 and a-z); 'ranges' (plural) was correct and the edit is a grammar regression in public docs. Consider reverting these wording changes.</violation>
</file>

<file name="deep_causality_cfd/src/solvers/dec/boundary/outflow.rs">

<violation number="1" location="deep_causality_cfd/src/solvers/dec/boundary/outflow.rs:24">
P3: The new class doc explicitly says this is NOT a zero-gradient outflow, but the inline comment in `collect_slip_edges` (line 76) still describes it as "A zero-gradient outflow." Since the PR is precisely about correcting this boundary's documentation, align the stale inline comment with the new pressure-reference framing so the two don't contradict.</violation>
</file>

<file name="deep_causality_cfd/src/theories/mod.rs">

<violation number="1" location="deep_causality_cfd/src/theories/mod.rs:12">
P3: The module doc lists `stokes_rhs`, but the actual free function and re-export are named `stokes_momentum_rhs` (and its wrapper is `stokes_momentum_rhs_effect`). A reader searching for `stokes_rhs` finds nothing; rename to `stokes_momentum_rhs` for accuracy and to match the `euler_*_rhs` wildcard style used alongside it.</violation>
</file>

<file name="deep_causality_cfd/src/solvers/dec/surface_force.rs">

<violation number="1" location="deep_causality_cfd/src/solvers/dec/surface_force.rs:73">
P3: The new docstring reference points at `deep_causality_cfd/papers/kirkpatrick2003.pdf`, but no PDF exists in the repo (the `papers/` dir holds only `README.md`, which itself incorrectly lists it as 'Present and cited'). The citation path is dangling, so readers will hunt for a file that isn't there; either add the PDF or drop the explicit path and keep the bibliographic reference.</violation>
</file>

<file name="deep_causality_cfd/src/navigation/nav_sensors.rs">

<violation number="1" location="deep_causality_cfd/src/navigation/nav_sensors.rs:51">
P3: The new sense_angular_rate has no dedicated unit test covering the non-zero gyro-bias add path; the sibling sense_specific_force has one (sensed_specific_force_adds_the_accel_bias), and every existing caller passes a zero rate, so the bias-add branch is only exercised at zero. Consider adding a test that asserts sensed == true + gyro_bias with a non-zero gyro bias, mirroring the accel test.</violation>
</file>

<file name="deep_causality_cfd/src/solvers/qtt/compressible/fitting.rs">

<violation number="1" location="deep_causality_cfd/src/solvers/qtt/compressible/fitting.rs:370">
P3: The added doc says `s` runs `0..1` and that the function returns the `peak n_e`. In the implementation `s = i / n_r` for `i in 0..n-1`, so `s` stops at `(n-1)/n` (never 1), and the returned `peak` is the equilibrium asymptote `α_eq·n₂` at `s→∞`, which the sampled field only approaches when `relax_length ≪ 1`. For `relax_length` near 1 the actual maximum in the QTT data is `peak·(1−e^{−s_max/L})` ≈ 0.63·peak — well below the reported value — so a caller comparing the returned `peak` to the ramp data will overstate the field's peak. Consider noting in the doc that the returned `peak` is the asymptotic equilibrium value, not necessarily the max of the sampled profile.</violation>
</file>

<file name="deep_causality_cfd/src/theories/compressible_ns.rs">

<violation number="1" location="deep_causality_cfd/src/theories/compressible_ns.rs:13">
P3: The module doc tells readers that deep_causality_physics ships "the ideal-gas pressure kernels" for an ideal-gas EOS closure, but no such p(ρ,e) ideal-gas pressure kernel exists there (only hydrostatic/bernoulli/dynamic and isentropic Mach-ratio pressure kernels). Consider naming the actual closure kernels or softening the claim so a reader looking for a density/energy-based EOS isn't led to a non-existent API.</violation>
</file>

<file name="deep_causality_cfd/src/types/flow/blackout.rs">

<violation number="1" location="deep_causality_cfd/src/types/flow/blackout.rs:439">
P3: The module-level doc comment at the top of this file still calls EosStage a 'two-temperature pressure' writer, which directly contradicts the new single-temperature doc this change introduces. This PR is meant to fix the two-temperature doc-overclaim (audit 10.11), so update the module-level summary at line 18 too, otherwise the same inaccurate phrasing remains published at the top of the module.</violation>
</file>

<file name="deep_causality_cfd/studies/qtt_blend_metric/output.txt">

<violation number="1" location="deep_causality_cfd/studies/qtt_blend_metric/output.txt:23">
P3: This finalized output fixture now diverges from the study's own README: the README still documents the older table (a `det J sign` column) and states 'The knee was not located (0.85/0.95 not run)', which directly contradicts the newly committed knee reading above λ≈0.75 (114→54 then 54→5). Since this PR finalizes the audit, updating README.md's table/narrative to match the fixture keeps the recorded reference consistent with its documentation.</violation>
</file>

<file name="openspec/specs/trajectory-nav-engine/spec.md">

<violation number="1" location="openspec/specs/trajectory-nav-engine/spec.md:21">
P3: The spec asserts concrete shipped priors (accel bias 1e-2, gyro bias 1e-8) that I could not find in the crate's source, tests, or avionics examples — the shipped covariance diagonals in tests/examples use constant [1.0;17]/[100.0;17]/[1e-6;17] values. If the code does not actually ship these priors, the sentence contradicts the crate it claims to specify; please align it with the real P0_DIAG/Q_DIAG or label the numbers as intended/example values rather than shipped ones.</violation>
</file>

<file name="deep_causality_cfd/verification/qtt_sod/baseline.txt">

<violation number="1" location="deep_causality_cfd/verification/qtt_sod/baseline.txt:1">
P3: The regex-matched "Finished `release` profile [optimized] target(s) in 0.22s" captures cargo's wall-clock build time, which is non-deterministic across machines and runs. Re-running the documented regeneration command (`cargo run --release -p deep_causality_cfd --example qtt_sod > baseline.txt 2>&1`) will never reproduce this exact line, so the committed reference baseline is not verbatim-reproducible. Consider trimming the cargo build-status preamble (or replacing the time with a fixed label) so the baseline records only the harness's deterministic output.</violation>
</file>

<file name="deep_causality_cfd/src/solvers/dec/mod.rs">

<violation number="1" location="deep_causality_cfd/src/solvers/dec/mod.rs:72">
P3: The new doc comment cites `deep_causality_cfd/papers/mohamed2016.pdf`, but that PDF is not in the repo (papers/ holds only README.md), and the papers index lists it as 'Present and cited' without the file. Align the convention: either add the PDF, or move this to the 'Cited in code, PDF not yet present' section in papers/README.md so the pointer isn't broken.</violation>
</file>

<file name="deep_causality_cfd/papers/README.md">

<violation number="1" location="deep_causality_cfd/papers/README.md:17">
P2: For an audit fixture, the '## Present and cited' table is the document's central claim, but the four PDFs it lists (kirkpatrick2003.pdf, Droege2005.pdf, mohamed2016.pdf, mittal2005.pdf) do not exist anywhere in the repository — `deep_causality_cfd/papers/` currently contains only this README, and the repo-wide search returns no PDFs. Since the whole point of the index is to make a physically-carried PDF tractable to its citing code, marking files as 'Present' when they are not committed makes the table misleading (note that the second section already handles this correctly with 'PDF not yet present'). Either add the PDFs as part of this change (the .gitignore comment says PDFs under papers/ are tracked intentionally) or move these rows to the not-yet-present section and state the PDFs have not been committed.</violation>
</file>

<file name="deep_causality_cfd/src/types/ambient.rs">

<violation number="1" location="deep_causality_cfd/src/types/ambient.rs:64">
P3: Doc claim is inaccurate: the snapshot writer does not record the body force — it refuses to serialize a body-forced ambient (returns Err) and only persists nu/freestream. So setting the body force does not 'change what is serialized'; it makes serialization fail. Suggest rewording to note the snapshot writer rejects body-forced ambients.</violation>
</file>

Note: This PR contains a large number of files. cubic only reviews up to 200 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.

Re-trigger cubic

Filter construction and restoration SHALL reject a covariance that fails the *necessary* covariance
conditions — a non-finite entry, an asymmetry beyond tolerance, or a negative variance on the diagonal —
rather than accepting arbitrary values and discovering the consequences during an update. A full
positive-semidefinite test (an LDLᵀ pivot scan) is deliberately **not** performed at the entry points: a

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: The scenario 'A non-PSD covariance is refused at construction' contradicts the revised requirement just above it. Since construction deliberately skips the full PSD/LDLᵀ check and only rejects necessary-condition violations, a symmetric non-PSD matrix with an all-positive diagonal (e.g. a round-off-negative eigenvalue from off-diagonal entries, like [[1,2],[2,1]]) still passes construction — so the title overpromises a rejection the spec and design (D3) both explicitly disclaim. Rename the scenario (and its WHEN) to what actually holds, e.g. 'A covariance violating a necessary condition is refused at construction', so a test author doesn't implement or expect a full-PSD rejection that won't occur.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At openspec/changes/archive/2026-07-24-fix-navigation-filter-correctness/specs/eskf-filter-correctness/spec.md, line 75:

<comment>The scenario 'A non-PSD covariance is refused at construction' contradicts the revised requirement just above it. Since construction deliberately skips the full PSD/LDLᵀ check and only rejects necessary-condition violations, a symmetric non-PSD matrix with an all-positive diagonal (e.g. a round-off-negative eigenvalue from off-diagonal entries, like [[1,2],[2,1]]) still passes construction — so the title overpromises a rejection the spec and design (D3) both explicitly disclaim. Rename the scenario (and its WHEN) to what actually holds, e.g. 'A covariance violating a necessary condition is refused at construction', so a test author doesn't implement or expect a full-PSD rejection that won't occur.</comment>

<file context>
@@ -69,13 +69,19 @@ and a negative one can drive `s` through zero from either side.
+Filter construction and restoration SHALL reject a covariance that fails the *necessary* covariance
+conditions — a non-finite entry, an asymmetry beyond tolerance, or a negative variance on the diagonal —
+rather than accepting arbitrary values and discovering the consequences during an update. A full
+positive-semidefinite test (an LDLᵀ pivot scan) is deliberately **not** performed at the entry points: a
+covariance produced by the Joseph update can carry a round-off-negative eigenvalue that a strict PSD test
+would wrongly reject, so the operational PSD backstop is the guarded measurement update above (which
</file context>

2d 64^2 cap 32: one rebuild ~ 0.00 steps; ~10 rebuilds/run adds 0.02% to the march

=== GO: corridor carrier 2d at 64^2, bond cap 32 (0.175 s/step, peak bond 32). ===
=== GO: corridor carrier 2d at 64^2, bond cap 32 (0.248 s/step, peak bond 32). ===

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: The freshly recorded reference output now measures the recommended config at 0.248 s/step (49.6 s corridor) and the 3-D shell at 3049 s, but README.md and studies/README.md still encode the previous run (0.175 s/step, 35 s corridor, 17x margin, 3-D 2161 s). This repo treats study output as gated evidence that must not silently change, so two authoritative sources now disagree on the recommended configuration's numbers; update both READMEs to match.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/studies/compressible_carrier_timing/output.txt, line 22:

<comment>The freshly recorded reference output now measures the recommended config at 0.248 s/step (49.6 s corridor) and the 3-D shell at 3049 s, but README.md and studies/README.md still encode the previous run (0.175 s/step, 35 s corridor, 17x margin, 3-D 2161 s). This repo treats study output as gated evidence that must not silently change, so two authoritative sources now disagree on the recommended configuration's numbers; update both READMEs to match.</comment>

<file context>
@@ -1,19 +1,28 @@
     2d         64^2 cap  32: one rebuild ~ 0.00 steps; ~10 rebuilds/run adds 0.02% to the march
 
-=== GO: corridor carrier 2d at 64^2, bond cap 32 (0.175 s/step, peak bond 32). ===
+=== GO: corridor carrier 2d at 64^2, bond cap 32 (0.248 s/step, peak bond 32). ===
+    Caveat on the cap: bond cap 32 is a COST parameter, carried forward untested for
+    accuracy. This study measures wall-clock only. No capped run is compared against an
</file context>


| PDF | Reference | Cited by |
|-----|-----------|----------|
| `kirkpatrick2003.pdf` | Kirkpatrick et al. (2003) | `src/solvers/dec/surface_force.rs` |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: For an audit fixture, the '## Present and cited' table is the document's central claim, but the four PDFs it lists (kirkpatrick2003.pdf, Droege2005.pdf, mohamed2016.pdf, mittal2005.pdf) do not exist anywhere in the repository — deep_causality_cfd/papers/ currently contains only this README, and the repo-wide search returns no PDFs. Since the whole point of the index is to make a physically-carried PDF tractable to its citing code, marking files as 'Present' when they are not committed makes the table misleading (note that the second section already handles this correctly with 'PDF not yet present'). Either add the PDFs as part of this change (the .gitignore comment says PDFs under papers/ are tracked intentionally) or move these rows to the not-yet-present section and state the PDFs have not been committed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/papers/README.md, line 17:

<comment>For an audit fixture, the '## Present and cited' table is the document's central claim, but the four PDFs it lists (kirkpatrick2003.pdf, Droege2005.pdf, mohamed2016.pdf, mittal2005.pdf) do not exist anywhere in the repository — `deep_causality_cfd/papers/` currently contains only this README, and the repo-wide search returns no PDFs. Since the whole point of the index is to make a physically-carried PDF tractable to its citing code, marking files as 'Present' when they are not committed makes the table misleading (note that the second section already handles this correctly with 'PDF not yet present'). Either add the PDFs as part of this change (the .gitignore comment says PDFs under papers/ are tracked intentionally) or move these rows to the not-yet-present section and state the PDFs have not been committed.</comment>

<file context>
@@ -0,0 +1,47 @@
+
+| PDF | Reference | Cited by |
+|-----|-----------|----------|
+| `kirkpatrick2003.pdf` | Kirkpatrick et al. (2003) | `src/solvers/dec/surface_force.rs` |
+| `Droege2005.pdf` | Dröge & Verstappen (2005) | `verification/dec_cylinder_verification/` (St and C_d reference bands) |
+| `mohamed2016.pdf` | Mohamed, Hirani & Samtaney (2016), "Discrete exterior calculus discretization of incompressible Navier–Stokes equations over surface simplicial meshes", J. Comput. Phys. 312:175–191 | `src/solvers/dec/mod.rs` (the DEC NS formulation this solver follows, on a periodic lattice complex rather than a surface simplicial mesh) |
</file context>

}

/// Generates a random `char` in ranges a-z and A-Z.
/// Generates a random `char` in range a-z and A-Z.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The doc comment now says a single 'range' while listing two disjoint ranges (a-z and A-Z, or 0-9 and a-z); 'ranges' (plural) was correct and the edit is a grammar regression in public docs. Consider reverting these wording changes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At thirdparty/crates/fastrand-2.5.0/src/global_rng.rs, line 88:

<comment>The doc comment now says a single 'range' while listing two disjoint ranges (a-z and A-Z, or 0-9 and a-z); 'ranges' (plural) was correct and the edit is a grammar regression in public docs. Consider reverting these wording changes.</comment>

<file context>
@@ -85,13 +85,13 @@ pub fn bool() -> bool {
 }
 
-/// Generates a random `char` in ranges a-z and A-Z.
+/// Generates a random `char` in range a-z and A-Z.
 #[inline]
 pub fn alphabetic() -> char {
</file context>
Suggested change
/// Generates a random `char` in range a-z and A-Z.
/// Generates a random `char` in ranges a-z and A-Z.

/// conservation). It carries no prescribed velocity: the outflow velocity is whatever the projection
/// produces, with the face's tangential edges left free.
///
/// This is a **pressure-reference** outflow, not a zero-gradient or convective one. No `∂u/∂n = 0`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The new class doc explicitly says this is NOT a zero-gradient outflow, but the inline comment in collect_slip_edges (line 76) still describes it as "A zero-gradient outflow." Since the PR is precisely about correcting this boundary's documentation, align the stale inline comment with the new pressure-reference framing so the two don't contradict.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/src/solvers/dec/boundary/outflow.rs, line 24:

<comment>The new class doc explicitly says this is NOT a zero-gradient outflow, but the inline comment in `collect_slip_edges` (line 76) still describes it as "A zero-gradient outflow." Since the PR is precisely about correcting this boundary's documentation, align the stale inline comment with the new pressure-reference framing so the two don't contradict.</comment>

<file context>
@@ -18,8 +18,13 @@ use super::boundary_zone::BoundaryZone;
+/// conservation). It carries no prescribed velocity: the outflow velocity is whatever the projection
+/// produces, with the face's tangential edges left free.
+///
+/// This is a **pressure-reference** outflow, not a zero-gradient or convective one. No `∂u/∂n = 0`
+/// condition and no boundary time-update `∂u/∂t + U_c·∂u/∂n = 0` is applied; the only thing imposed is
+/// `φ = 0` on the face's vertices. That is sufficient to make the open-boundary Poisson problem
</file context>

# Opt-in CPU parallelism. Forwards to the topology crate's Rayon-backed DEC
# operator loops and the shared `MaybeParallel` marker. Serial by default;
# CPU parallelism. Forwards to the topology crate's Rayon-backed DEC operator
# loops and the shared `MaybeParallel` marker. On in the `default` set above;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The newly added comment sentence On in the \default` set above;doesn't read clearly — it looks like the intended wording was something like "It is on in thedefaultset above" or "On by default (it sits in thedefaultset above)". Since this comment is the crate's documentation of how to select serial vs. parallel builds, the broken sentence makes the guidance harder to follow. Consider rewording, e.g. "It is on in thedefault` set above; build with ..."

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/Cargo.toml, line 52:

<comment>The newly added comment sentence `On in the \`default\` set above;` doesn't read clearly — it looks like the intended wording was something like "It is on in the `default` set above" or "On by default (it sits in the `default` set above)". Since this comment is the crate's documentation of how to select serial vs. parallel builds, the broken sentence makes the guidance harder to follow. Consider rewording, e.g. "It is on in the `default` set above; build with ..."</comment>

<file context>
@@ -48,8 +48,11 @@ std = [
-# Opt-in CPU parallelism. Forwards to the topology crate's Rayon-backed DEC
-# operator loops and the shared `MaybeParallel` marker. Serial by default;
+# CPU parallelism. Forwards to the topology crate's Rayon-backed DEC operator
+# loops and the shared `MaybeParallel` marker. On in the `default` set above;
+# build with `--no-default-features --features std` for the serial loops. The
+# Rayon fan-out costs more than it saves on small grids, so serial is the faster
</file context>
Suggested change
# loops and the shared `MaybeParallel` marker. On in the `default` set above;
+# loops and the shared `MaybeParallel` marker. It is on in the `default` set above;

// Opt-in QMC collapse uses a per-sample reproducible Sobol shift (base ⊕ id), so
// Opt-in QMC collapse uses a per-sample reproducible Sobol shift, `base + id`
// with wrapping addition (not an XOR digital shift), so each step is an
// independent randomized-QMC realization; default is the MC mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The rewording of this comment left a duplicated line: the newly added // independent randomized-QMC realization; default is the MC mean. is immediately followed by the pre-existing // each step is an independent randomized-QMC realization; default is the MC mean., which says the same thing twice. Drop the redundant trailing line so the comment reads once.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/src/solvers/dec/uncertain_inflow/uncertain_boundary_source.rs, line 147:

<comment>The rewording of this comment left a duplicated line: the newly added `// independent randomized-QMC realization; default is the MC mean.` is immediately followed by the pre-existing `// each step is an independent randomized-QMC realization; default is the MC mean.`, which says the same thing twice. Drop the redundant trailing line so the comment reads once.</comment>

<file context>
@@ -135,7 +142,9 @@ where
-                // Opt-in QMC collapse uses a per-sample reproducible Sobol shift (base ⊕ id), so
+                // Opt-in QMC collapse uses a per-sample reproducible Sobol shift, `base + id`
+                // with wrapping addition (not an XOR digital shift), so each step is an
+                // independent randomized-QMC realization; default is the MC mean.
                 // each step is an independent randomized-QMC realization; default is the MC mean.
                 let collapsed = match self.qmc_collapse_seed {
</file context>

Comment thread deep_causality_cfd/studies/qtt_rank_3d/output.txt Outdated
/// diagonal. The round-trip `Q_step × 10 × 0.1` is bit-exact for the position, velocity, attitude,
/// accel-bias and clock-bias blocks; for the gyro-bias and clock-drift blocks (`1e-14`) it differs by
/// ≤1 ULP (`1e-13 × 0.1 ≠ 1e-14` in `f64`), far below any observable effect, so the filter's behaviour at
/// `DT_FLIGHT` is unchanged **at every displayed figure** (see the discretisation note on `NavFilter::predict`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: The rewritten Q_DIAG doc claims that re-expressing the process noise as a continuous-time spectral density leaves "the filter's behaviour at DT_FLIGHT unchanged at every displayed figure", but the committed outputs in this same PR show the nav figures did change. The corridor output.txt diffs position variance = 2.6711e1 m^22.6710e1 m^2 on the peak leg and nav error vs truth = 0.2802 m0.2804 m on reacquisition, and the weather table's drift_mean/drift_sd values also all moved. The doc itself concedes the gyro-bias/clock-drift blocks (1e-14) only round-trip to ≤1 ULP, which is enough to perturb the filter over the couple-of-hundred-step descent into the displayed 4th decimal. So the "unchanged at every displayed figure" assertion is not borne out by the artifacts. Consider softening the claim (e.g. "no observable effect on the displayed figures at the stated precision") or noting the small drift variables' ULP differences do surface in the published numbers, so the doc and the committed outputs are consistent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At examples/avionics_examples/src/shared/constants.rs, line 194:

<comment>The rewritten Q_DIAG doc claims that re-expressing the process noise as a continuous-time spectral density leaves "the filter's behaviour at DT_FLIGHT unchanged **at every displayed figure**", but the committed outputs in this same PR show the nav figures did change. The corridor `output.txt` diffs `position variance = 2.6711e1 m^2` → `2.6710e1 m^2` on the peak leg and `nav error vs truth = 0.2802 m` → `0.2804 m` on reacquisition, and the weather table's `drift_mean`/`drift_sd` values also all moved. The doc itself concedes the gyro-bias/clock-drift blocks (`1e-14`) only round-trip to ≤1 ULP, which is enough to perturb the filter over the couple-of-hundred-step descent into the displayed 4th decimal. So the "unchanged at every displayed figure" assertion is not borne out by the artifacts. Consider softening the claim (e.g. "no observable effect on the displayed figures at the stated precision") or noting the small drift variables' ULP differences do surface in the published numbers, so the doc and the committed outputs are consistent.</comment>

<file context>
@@ -169,15 +179,26 @@ pub const P0_DIAG: [f64; 17] = [
+/// diagonal. The round-trip `Q_step × 10 × 0.1` is bit-exact for the position, velocity, attitude,
+/// accel-bias and clock-bias blocks; for the gyro-bias and clock-drift blocks (`1e-14`) it differs by
+/// ≤1 ULP (`1e-13 × 0.1 ≠ 1e-14` in `f64`), far below any observable effect, so the filter's behaviour at
+/// `DT_FLIGHT` is unchanged **at every displayed figure** (see the discretisation note on `NavFilter::predict`).
 pub const Q_DIAG: [f64; 17] = [
-    1.0e-4, 1.0e-4, 1.0e-4, // position
</file context>

/// applies to the rate kernel each call, the ambient body force is **not** read by any rate: the DEC
/// solver takes its body force at construction (`DecNsRate`'s own `g♭`, supplied via the config or a
/// `BodyForceZone`), and the QTT marchers do not read `Ambient` at all. The only in-crate reader is
/// the snapshot writer, which records it. So setting it here changes what is serialized, not what is

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: Doc claim is inaccurate: the snapshot writer does not record the body force — it refuses to serialize a body-forced ambient (returns Err) and only persists nu/freestream. So setting the body force does not 'change what is serialized'; it makes serialization fail. Suggest rewording to note the snapshot writer rejects body-forced ambients.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/src/types/ambient.rs, line 64:

<comment>Doc claim is inaccurate: the snapshot writer does not record the body force — it refuses to serialize a body-forced ambient (returns Err) and only persists nu/freestream. So setting the body force does not 'change what is serialized'; it makes serialization fail. Suggest rewording to note the snapshot writer rejects body-forced ambients.</comment>

<file context>
@@ -56,6 +56,14 @@ impl<R: CfdScalar> Ambient<R> {
+    /// applies to the rate kernel each call, the ambient body force is **not** read by any rate: the DEC
+    /// solver takes its body force at construction (`DecNsRate`'s own `g♭`, supplied via the config or a
+    /// `BodyForceZone`), and the QTT marchers do not read `Ambient` at all. The only in-crate reader is
+    /// the snapshot writer, which records it. So setting it here changes what is serialized, not what is
+    /// marched. To drive a body force per step, the rate kernel needs a `set_body_force` mirroring
+    /// `set_nu`; that is a follow-up, not present today.
</file context>

…sioning, and doc accuracy

 Acts on a code review of the audit-remediation work. Twenty-one findings were
 raised; nineteen hold and are fixed here, one is refuted with measurement, and
 four navigation items are escalated rather than patched because each moves
 marched numbers and none is an unambiguous bug fix.

 Navigation error paths, the substantive half:

 - ReentryNavEngine::predict committed state before its fallible stages. Attitude
   was integrated before ks_strang_step, and position/velocity before the
   relativistic clock kernel, so a refusal returned Err with the engine partially
   advanced: attitude carrying w*dt of rotation while tau_offset and elapsed stood
   still. A retry then integrated the gyro a second time from the wrong
   orientation, which no position-variance check can catch. Every fallible stage
   now runs against locals and commits afterwards, with NavFilter::predict first
   because it validates before it mutates. Arithmetic and operand order are
   unchanged.
 - NavFilter::predict read dt and the process-noise diagonal unchecked. A
   non-finite dt NaNs the whole covariance; a negative dt subtracts |dt|*Q_c from
   the diagonal and leaves negative variances behind a call that returned (). It
   now returns Result and refuses a non-finite or non-positive dt and any negative
   or non-finite spectral density, before touching state. Zero remains admissible.
   The only in-workspace callers are the engine and this crate's tests.
 - TrajectoryNav consumed the optical fix before attempting the GNSS fold, so a
   refused GNSS correction dropped an unread optical measurement. The optical take
   is deferred until after the GNSS block. Deferring beats restoring on error:
   there is no error path left to get wrong, and a fix that was attempted and
   refused still stays consumed.

 Snapshot format. The attitude work added four floats to the nav section of the
 resume format without versioning it, so the two directions failed differently: a
 v1 package read by this build failed as "truncated" while naming the wrong cause,
 and a v2 package read by a pre-attitude build parsed the quaternion as the head of
 the filter state and shifted everything after it. The nav section is now written
 at version 2 behind a helper that refuses unknown versions, and v1 decodes with
 the identity attitude. That decode is lossless rather than merely safe: the build
 that wrote v1 carried no attitude and propagated under C = I, which is the
 identity quaternion exactly, so a v1 resume reproduces the suspended engine
 instead of inventing a heading. Bumping is what makes an older build refuse a v2
 package on its own version check; rejecting v1 alone could not do that.

 Documentation accuracy:

 - strip_pressure_force claimed its result is "Pa*m^2 ... not a force (N)", which
   is self-contradictory: Pa*m^2 is exactly N. The objection was written as a
   dimensional claim when it is a geometric one. The dimensions are those of a
   force; the quantity is not one, because it is an isotropic scalar accumulated
   over a region while a force is a traction integrated over a surface, with no
   outward normal and so no direction.
 - solve_poisson promised that only the constant mode is zeroed. sin(2*pi*k/N)
   also vanishes at Nyquist, so four modes are discarded: the constant, both
   axis-aligned checkerboards, and the collocated one. The project doc had been
   updated for this; the Poisson doc one level down had not.
 - The dec_taylor_green_re1600 peak/endpoint label chose its maximum with a strict
   >, which keeps the first occurrence, so a final sample tying an earlier maximum
   was reported as an interior turnover. A terminal plateau is now its own case.
   The shipped 16^3 run rises strictly to the end, so its printed label and every
   number are unchanged.
 - LegSet::rebuilds still documented the deleted rebuild_count helper and its
   log-substring strategy; the field is now summed from per-leg pause.rebuilds().

 Committed fixtures leaked an absolute path. nozzle_operating_map/output.txt began
 with cargo's "Compiling ... (/Users/<name>/...)" preamble, disclosing a username
 and directory layout. Root cause is mine: I regenerated fixtures with `2>&1`, and
 cargo writes that line to stderr. Sweeping for the same mistake found three more
 files I had contaminated the same way (qtt_rank_nonlinear, qtt_rank_3d and
 compressible_carrier_timing outputs). All four are cleaned, gate lines and
 measured numbers intact, and each ends in exactly one newline. The nozzle fixture
 needed that newline appended by hand: the verdict prints through print!, which
 emits none, and the sibling fixtures all carry one. Pre-existing occurrences in
 archived openspec documents and one committed weather audit log are untouched and
 flagged.

 Stale references. Eight path and line references were wrong, five of them because
 the audit notes moved from openspec/notes/ to openspec/audits/ and three because
 line numbers drift. Line references are replaced with symbol references
 (SMOOTH_CELLS, ETA, shock_floor, render_ladders, summary()) rather than
 renumbered, since renumbering only resets the clock on the same defect. A
 documentation-code-parity requirement cited src/types/flow/gates.rs, which no
 longer exists; its supporting prose is now past tense and names the change that
 retired the type, so the requirement still reads as a live contract while its
 evidence reads as history. Two further broken links were found beyond the report.

 One finding refuted, with the measurement rather than an argument. The claim was
 that predict reintroduces float asymmetry fast enough for a long predict-only run
 to be rejected by restore's symmetry check. The mechanism is real, the consequence
 is not: after 5000 predict steps the worst asymmetry is 3.4e-7 of the admitted
 band, and after 50,000 steps 8.6e-7, a sqrt(N) walk that would need order 1e16
 steps to matter. Re-symmetrising would perturb every marched number to fix
 nothing. A test now pins the ratio and asserts restore accepts.

 Four navigation items are escalated, not fixed, because each moves marched numbers
 and each is a modelling decision rather than a defect with one right answer:

 - The aero channel is fed raw to ks_strang_step but rotated by C(q) for the
   filter, so the two disagree once the vehicle is off identity. Tracing the
   producers (BankSteeredLift, AeroForceCoupling, PlumeObstruction) shows the
   channel is built in the inertial frame, which makes the filter side the one
   applying a second rotation. That contradicts the design's own premise, so the
   fix is a frame-convention decision.
 - nav_transition_matrix is half-linearised about the nominal attitude: the -[f]x
   block is evaluated there, but both bias couplings still carry -dt where a
   nav-frame ESKF wants -C(q)*dt.
 - correct_position injects a nonzero attitude error and resets without applying
   the reset Jacobian, so the covariance stays in pre-injection coordinates.
 - restore accepts symmetric matrices with a non-negative diagonal, which is not
   PSD. D3's premise was tested rather than trusted: an LDL^T probe over 2000
   predict-and-fold cycles produced no negative pivot, so the false-rejection case
   D3 cites did not reproduce. Pivots do reach 1e-6 of the diagonal, so any
   tolerance is a live tuning risk, which is why the gate is the owner's call.

 Ten regression tests added, all behavioural through the public API. bazel test
 //...: 1153/1153 pass. cargo test -p deep_causality_cfd --release: 910 passed, 0
 failed (894 before). clippy --all-targets --all-features -D warnings: clean across
 cfd, physics and avionics_examples, no new #[allow]. Rustdoc warnings unchanged at
 9. Both openspec specs validate --strict. plasma_blackout_corridor reproduces its
 committed output byte for byte, including leg4 0.2804 m and leg2 variance
 2.6710e1 m^2, with all 14 gates passing.

 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 22 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="deep_causality_cfd/src/navigation/eskf.rs">

<violation number="1" location="deep_causality_cfd/src/navigation/eskf.rs:207">
P1: A non-finite `specific_force` still makes `predict` report success after poisoning filter state and covariance; validate its three components before the first mutation, alongside `dt` and process noise.</violation>
</file>

<file name="openspec/specs/documentation-code-parity/spec.md">

<violation number="1" location="openspec/specs/documentation-code-parity/spec.md:102">
P2: This paragraph asserts the Taylor–Green harness reports 'clean 2nd-order convergence' without qualifying it as 2nd-order-in-space/1st-order-in-time and without documenting the temporal floor or max ladder length, yet the three sources it cites (summary() at print_utils.rs:143, the README 'Measured' section, and verification/README.md:334-336) now state exactly that qualification and document the floor and max usable length. The paragraph is stale and contradicts the code it references — the precise defect this documentation-code-parity spec exists to catch. Reframe it in the past tense like the Gates paragraph in the same diff, or drop the 'without qualifying/without documenting' claims.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

pub fn predict(
&mut self,
dt: R,
specific_force: [R; 3],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: A non-finite specific_force still makes predict report success after poisoning filter state and covariance; validate its three components before the first mutation, alongside dt and process noise.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deep_causality_cfd/src/navigation/eskf.rs, line 207:

<comment>A non-finite `specific_force` still makes `predict` report success after poisoning filter state and covariance; validate its three components before the first mutation, alongside `dt` and process noise.</comment>

<file context>
@@ -184,14 +184,54 @@ impl<R: RealField> NavFilter<R> {
+    pub fn predict(
+        &mut self,
+        dt: R,
+        specific_force: [R; 3],
+        process_noise_diag: [R; NAV_STATES],
+    ) -> Result<(), PhysicsError> {
</file context>

The QTT Taylor–Green harness reports "clean 2nd-order convergence" (the "Measured" section of
`verification/qtt_taylor_green_verification/README.md`, `summary()` in
`verification/qtt_taylor_green_verification/print_utils.rs`, and the `qtt_taylor_green_verification`
section of `verification/README.md`) without qualifying it as second-order in space and first-order in

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: This paragraph asserts the Taylor–Green harness reports 'clean 2nd-order convergence' without qualifying it as 2nd-order-in-space/1st-order-in-time and without documenting the temporal floor or max ladder length, yet the three sources it cites (summary() at print_utils.rs:143, the README 'Measured' section, and verification/README.md:334-336) now state exactly that qualification and document the floor and max usable length. The paragraph is stale and contradicts the code it references — the precise defect this documentation-code-parity spec exists to catch. Reframe it in the past tense like the Gates paragraph in the same diff, or drop the 'without qualifying/without documenting' claims.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At openspec/specs/documentation-code-parity/spec.md, line 102:

<comment>This paragraph asserts the Taylor–Green harness reports 'clean 2nd-order convergence' without qualifying it as 2nd-order-in-space/1st-order-in-time and without documenting the temporal floor or max ladder length, yet the three sources it cites (summary() at print_utils.rs:143, the README 'Measured' section, and verification/README.md:334-336) now state exactly that qualification and document the floor and max usable length. The paragraph is stale and contradicts the code it references — the precise defect this documentation-code-parity spec exists to catch. Reframe it in the past tense like the Gates paragraph in the same diff, or drop the 'without qualifying/without documenting' claims.</comment>

<file context>
@@ -96,10 +96,12 @@ it holds. A claim of "n-th order convergence" that is n-th order in space and a
+The QTT Taylor–Green harness reports "clean 2nd-order convergence" (the "Measured" section of
+`verification/qtt_taylor_green_verification/README.md`, `summary()` in
+`verification/qtt_taylor_green_verification/print_utils.rs`, and the `qtt_taylor_green_verification`
+section of `verification/README.md`) without qualifying it as second-order in space and first-order in
+time, and without documenting the temporal-error floor (~1e-5 at fixed `dt`) or the ladder's maximum
+usable length.
</file context>

Comment thread deep_causality_cfd/README.md Outdated
Comment thread deep_causality_cfd/README.md Outdated
Comment thread deep_causality_cfd/README.md Outdated
Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
@marvin-hansen
marvin-hansen merged commit 1cd5c7a into deepcausality-rs:main Aug 10, 2026
20 of 21 checks passed
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