21cefaee

Author: Lucien Huber <im@lcnbr.ch>

Committer: GitHub <noreply@github.com>

Disconnected UV (#93)

* Make scalar Yukawa UV algebra explicit and clarify cut groups

Replace the CP-even scalar FFS4 Lorentz structure ProjM + ProjP with Identity in the canonical SM UFO and both checked-in SM JSON representations. This makes the exact gamma5 cancellation explicit before dimension-dependent Dirac and UV-reduction algebra, fixing the finite integrated UV contribution for Higgs Yukawa vertex corrections while retaining genuinely chiral and pseudoscalar projectors.

Audit the cross-section cut partition terminology and rename the internal RaisedCutId, RaisedCutData, and RaisedCutGroup concepts to CutGroupId, CutGroupData, and CutGroup. These groups cover ordinary order-one Cutkosky cuts as well as truly raised cuts, so propagate the precise naming through parametric integrands, dual shapes, threshold counterterms, event evaluation, IR analysis, diagnostics, and integrand metadata while leaving actual raised propagator and raised E-surface concepts unchanged.

Rename standalone cross-section archive data from raised_cut_integrands to cut_group_integrands and bump the archive schema to version 6. Extend the standalone export regression to assert the new field and reject the obsolete name. Keep the known aa_aa ARM/SymJIT backend-consistency test out of the curated test_gammaloop recipe until Symbolica updates its pinned SymJIT dependency, without deleting or weakening the test itself.

Validated with just fmt, cargo check, just clippy, targeted raised-cut/raised-threshold/mass-shift/LMB and standalone tests, and the complete just test_gammaloop suite under warnings-as-errors. Five-core summed-OSE checks gave GL30 = -1.18403(141)e-4 versus -1.18480e-4 and GL22 = -9.0530(92)e-5 versus -9.1283e-5, both within one standard deviation of their benchmarks and with no non-finite evaluations.

* Address cut-group review feedback

Keep the test_gammaloop nextest profile filter active for normal and important-only runs. Bypass it only when slow or failing classes are explicitly selected, while retaining the separate known ARM/SymJIT exclusion.

Correct max_occurrence and cutkosky_cut_union spellings in the touched cross-section evaluation and threshold-construction paths. Validated with just fmt, just clippy, and the complete just test_gammaloop suite.

* Restore global physical-cut exclusion from threshold subtraction

The cut-relative threshold-classification refactor accidentally changed skip_thresholds_that_are_cuts from a graph-wide candidate filter into a comparison against only the physical cut currently being processed. That allowed one physical Cutkosky surface to be generated as a threshold counterterm for another cut, producing rare pathological tails in GL18 and GL20 and making summed LMB multichanneling expose unstable integration behavior.

Restore the original graph-wide semantics at threshold-counterterm generation time. Filter CT candidates against every physical cut before constructing any per-cut association, while retaining all topology-discovered E-surfaces in the graph inventory for display and metadata. The comparison remains an exact topology-level OrientedCut comparison, is model and graph independent, and adds no evaluation-time work.

Add a regression that verifies physical-cut E-surfaces remain visible in the topology inventory but never appear in generated left/right threshold associations when the setting is enabled. Add a self-contained production-style GL20 local-inspect regression that generates the fully grouped NLO graph, enables summed OSE LMB multichanneling, evaluates the former high-weight point, and snapshots all 16 generated events including channel basis metadata, cuts, momenta, event weights, and every additional weight. Give this intentionally expensive evaluator-construction test an explicit five-minute Nextest timeout in local and CI profiles.

Validation: cargo fmt --all -- --check; just clippy -- -D warnings; targeted physical-cut association regression; GL20 snapshot generation/test. Five-core grouped summed-OSE integrations produced GL18 re = +1.36158e-4 +/- 3.25577e-6 (0.44 sigma from +1.3472e-4) over 200k points and GL20 re = +2.17036e-4 +/- 5.49820e-6 (1.51 sigma from +2.0875e-4) over 300k points, with no NaN or unstable samples.

* Harden iterated threshold counterterms and subspace centers

Correct the storage invariant for iterated LU threshold counterterms. The collection is emitted in left-major/right-minor order, so indexing now uses the number of right thresholds as the row stride. Construction validates the complete left-by-right shape, helper construction passes both dimensions explicitly, and asymmetric 2x3 and 3x2 regressions prevent the previous square-only assumption from returning.

Carry that invariant through standalone evaluator export and loading. Persist the right-threshold count, validate stored dimensions against the independently loaded left and right collections before accepting an archive, and bump STANDALONE_EVALUATORS_VERSION to 7 so incompatible archives fail at the format boundary instead of being silently misindexed.

Keep forced LU overlap centers inside their declared active subspace after probe rotation and affine parent-LMB transformation. Inactive loop coordinates are projected to zero before center validation and subtraction, preserving the sampled fixed complement. Extend the multidimensional subspace regression with a non-default parent LMB and nonzero external shifts that would otherwise populate an inactive component.

Reject negative and non-finite generation/runtime E-surface existence tolerances during deserialization, expose the nonnegative bound in generated schemas, and defensively normalize or restore the default for settings mutated programmatically. Add regressions for zero, negative, NaN, and infinite values.

Validation: cargo fmt --all -- --check; targeted gammalooprs unit regressions for asymmetric iterated indexing, fixed-complement center projection, settings deserialization, and programmatic E-surface tolerance handling; just clippy -- -D warnings.

User request: Ok, actually, commit+push your existing fix already, I want to run a fixed deep re-run on the cluster already.

* guard saturated progress ETAs and contextualize UV unions

Centralize the progress style used by long-running bounded operations and
override Indicatif's `eta_precise` formatter with a saturation-aware renderer.
Indicatif represents an overflowing ETA as `Duration::MAX`; formatting that
sentinel produced values such as `213503982334601d 07:00:15`. Render only that
sentinel as `--:--:--`, while preserving the standard precise duration format
for every finite ETA.

Use the shared style consistently for:

- FeynGen diagram generation;
- aggregate integrand-generation progress; and
- parallel `approach` sample evaluation.

This removes duplicate templates and ensures all affected progress paths get
the same overflow handling and cyan/blue bar styling.

Add the diagram name, UV forest node identifier, and parent count to the
unsupported-union panic. This keeps the existing intentional failure for
disconnected UV forests, but makes a large parallel generation run identify
the exact graph and structural condition that needs support.

Bump the GammaLoop package version from 0.3.3 to 0.3.4 in the Rust and Python
package metadata and synchronize Cargo.lock and uv.lock.

Validation:

- `cargo fmt --all -- --check`
- `cargo test -p gammalooprs utils::progress::tests --lib`
- `cargo check --locked -p gammalooprs -p gammaloop-api`
- `cargo clippy --locked -p gammalooprs -p gammaloop-api --lib -- -D warnings`
- parsed the NNLO run card and checked its generated selection command
- checked 0.3.4 consistency across package metadata and lockfiles

All builds, diagnostics, and tests after the watchdog request ran under a
30 GB aggregate-RSS process-tree watchdog.

User prompt:

I'm now running some epem_a_tth_NNLO diagram selection with:
`./gammaloop --release --clean-state ./examples/cli/epem_a_ttxh/NNLO/epem_a_tth_NNLO.toml run generate_diagrams generate_integrands` (do not run it)

and during generation (which is going fine otherwise so far) the ETA of the progressbar becomes silly with random numbers (prolly an overflow or negative) number, e.g. like this:
```
[00:08:00 | ETA: 213503982334601d 07:00:15]
```
Can you fix it?

Also, unrelated, but can you add more context to this message so that the diagram name concerned is given?
```
Message:  not implemented: Union not implemented
Location: crates/gammalooprs/src/uv/forest.rs:294
```

Follow-up user prompt:

pull latest, version and then commit+push this small change. Also, collect all epem_a_tth_NNLO graphs with this error during generation (which is expected and understood, it has to do with support for disconnect UV graphs which we have pending in another branch) after running:
`select -p epem_a_tth -i NNLO --amplitude-graphs --without-raised-propagator-signatures ANY_RAISING --without-raised-cuts-signatures ANY_RAISING`
and then add them as veto with `--without-graph-names`.

You can run what you need  for this identification in `./examples/cli/epem_a_ttxh/NNLO_experiment`, but you'll need to be clever because you ideally don't want to pay the full generation price to reach that error and you also don't want to get these erroneous diagrams one at a time.

* track the epem ttH NNLO run card

Make the e+ e- -> t t~ H NNLO command card a maintained example while
continuing to ignore every other generated or experimental artifact in its
directory.

- replace the directory-wide NNLO ignore rule with an explicit contents rule
  and a single exception for epem_a_tth_NNLO.toml
- retain the existing gammaloop_state ignore coverage so generated diagrams,
  integrands, compiled data, and integration workspaces cannot be committed
  accidentally
- add the complete NNLO workflow for diagram and integrand generation,
  integration, model setup, differential selectors, and observables
- select only amplitude graphs without raised propagator or cut signatures
- veto GL168, GL568, GL592, GL648, GL672, GL673, and GL677, whose disconnected
  UV forests currently require the pending Union implementation
- preserve the diagnostic subset annotation used while identifying the veto

Validation:
- parse epem_a_tth_NNLO.toml with Python tomllib
- assert the amplitude/no-raising filters and exact seven-graph veto list
- verify generated NNLO gammaloop_state paths remain ignored

User prompt:
adjust gitignore so that ./examples/cli/epem_a_ttxh/NNLO/epem_a_tth_NNLO.toml is tracked annd commit+push this NNLO run card with descriptive message

* fix parallel generation progress reporting

Make aggregate integrand-generation progress represent completed work rather
than Indicatif tick activity, which could decay toward a zero rate during long
per-graph stages and render finite but absurd multi-million-day ETAs.

- estimate ETA from elapsed time and completed work units instead of the
  smoothed recent tick rate
- render ETA as N/A while the parallel completion sample is immature and for
  unavailable or overflowing estimates
- track cross-section graph-generation progress with completed cuts plus fully
  completed graphs, preserving both granular updates and terminal work
- distinguish graph preprocessing from cut discovery and count a graph as done
  only after cuts, CFFs, LMBs, parametric integrands, and threshold CTs finish
- replace irrelevant preprocessing timing percentages with a concise summary
  of the preprocessing stages
- display graph status as done (currently active) / total, with the complete
  active-count parenthetical dimmed
- retain the detailed expression, Spenso, Symbolica-evaluation, and compilation
  timing shares for phases where those measurements exist
- cover ETA overflow, warmup, average-throughput estimation, preprocessing
  completion semantics, combined progress units, and active/done graph counts

Validation:
- cargo test -p gammalooprs utils::progress::tests --lib -- --test-threads=1
- cargo test -p gammaloop-api aggregate_generation_progress --lib -- --test-threads=1
- cargo clippy -p gammalooprs -p gammaloop-api --lib -- -D warnings
- cargo fmt --all -- --check

User prompt:
(ok but the two parenthesis themselves should be dimmed too. the commit + push this small fix.

* Fix iterated threshold helper symbol families

Build iterated threshold-counterterm helpers from distinct left and right inverse-map functions instead of leaving both sides under the generic eta family. Expand the product before applying the existing wildcard replacements so arbitrary supported products of left/right derivatives of the formal numerator are fused into the corresponding bivariate derivatives.

Register eta, eta_left, and eta_right in the existing global GammaloopSymbols repository and use those canonical symbols throughout threshold helper generation, parameter construction, tests, and the implicit r-star evaluator. This makes symbol initialization deterministic and keeps expression and evaluator parameter identities aligned.

Add graph, cut-group, CFF-index, and subspace-loop context to iterated-helper construction errors. Add a regression that constructs evaluators for every left/right threshold order through 3x3, while retaining generic implementation support for all requested orders.

Validated before commit with focused iterated-threshold and r-star evaluator tests, formatting, and clippy. The complete test_gammaloop suite is running as a post-push verification.

* feat(integrate): support runtime graph-group subsets

Add sampling.graph_names as a runtime-only graph-group filter for Monte Carlo graph sampling. Validate duplicate, unknown, non-master, and incompatible selections, preserve generated group order, and expose the setting through serialization and generated schemas.

Construct ephemeral amplitude and cross-section integration views from complete selected groups using the existing graph-group selection machinery. Clone only retained graph terms and matching amplitude group metadata, rebuild compact group bookkeeping, preserve generated evaluators, cuts, thresholds, orientations, and LMB data, retain the active backend, and reset only runtime event caches.

Warm and clone the reduced view for integration workers without warming or mutating the full source integrand. Keep workspace resume validation tied to the full generated-integrand fingerprint while persisting the selected runtime settings, and require restart before changing a resumed subset.

Update shared tabled and ratatui monitoring so selected groups are the reported graph grid and an explicit one-group subset retains a one-bin graph breakdown. Add parser, structural amplitude and cross-section, numerical normalization, event metadata, worker-view, monitoring, schema, and workspace resume coverage.

Validated with cargo check, formatting, workspace clippy, targeted regressions, and the complete just test_gammaloop suite (1419 passed, 151 skipped).

* fix amplitude threshold specialization and display metadata

Make generation-time positive-external-energy filtering conservative and energy-conservation aware. Derive the incoming/outgoing partition from graph edge flow, retain surfaces already proven existing at the configured point, and preserve every remaining surface whose shift is strictly negative for all positive external energies modulo the external energy-conservation relation. Keep runtime validation as the safety boundary when model parameters or external kinematics differ from the specialized generated state.

Expose a stable pointwise E-surface classification for API consumers. Aggregate amplitude classifications across all members of a graph group, retain the representative source graph for each displayed surface, report amplitude classifications instead of cross-section cut activity, and propagate the new metadata through JSON and Python wrappers. Match generation LMBs by their loop-edge set so harmless edge ordering differences no longer hide the selected basis.

Initialize GammaLoop tracing before importing Symbolica state so import warnings cannot install a fallback subscriber and cause escaped ANSI sequences in later tables.

Update the qq_hhh_2L cards with complete default external kinematics and multicore settings. Enable current-model and positive-energy generation checks in the production card. Keep the Euclidean MT=750 configuration aligned between generation and runtime at xi=p1+p2=(1000,0,0,0), use a matching workspace label, and retain its lightweight local integration settings.

Generated amplitude states using the old positive-energy filter should be regenerated when they rely on subset external-energy thresholds. Runtime validation continues to reject incompatible specialized states with model-and-kinematics context.

Validation:
- just test_gammaloop: 1421 passed, 151 skipped
- just check
- just fmt
- just clippy

User request:
Can you run `just test_gammaloop` and validate your changes so far and commit+push (and also including my changes to `./examples/cli/qq_hhh_2L/qq_hhh_2L.toml` and `./examples/cli/qq_hhh_2L/qq_hhh_euclidean_2L.toml`)

* fix(subtraction): configure radial-root residual tolerance

Replace the hard-coded eight-epsilon residual multiplier used by threshold-counterterm radial root validation with the runtime subtraction setting radial_root_residual_tolerance.

Default the dimensionless multiplier to 1000 and continue scaling it by the epsilon of the active numerical precision and E_cm. Apply the same setting consistently to LU cross-section and amplitude threshold counterterms so precision rescue uses one policy across both integrand kinds.

Reject negative and non-finite values during deserialization, regenerate the runtime and run-history schemas, and cover the default, explicit overrides, and invalid inputs with a focused settings test.

* Improve amplitude preprocessing progress reporting

Initialize aggregate preprocessing progress for amplitude generation in both full-process and direct-integrand entry paths, using the generated amplitude graph count as the progress total.

Report graph start and completion events from the existing parallel amplitude preprocessing loop so the progress bar exposes completed and active graph counts instead of remaining at 0/0. Keep cross-section reporting unchanged, omit the inapplicable cut counter for amplitudes, and show the amplitude-specific CFF, LMB, integrand, threshold-counterterm, and tropical-sampler stages.

Add a regression test for amplitude preprocessing progress state transitions. Route exact numerator-aware grouping cancellation details through structured debug logging instead of printing symbolic expressions directly to stdout.

Refresh the deterministic GL20 multichannel local-inspect snapshot after the radial-root residual-tolerance update. The changed values are confined to numerical-zero imaginary and threshold-counterterm components; physical real event weights and metadata are unchanged.

Validation: cargo fmt --all -- --check; just clippy; just test_gammaloop (1425 passed, 151 skipped).

* validate radial roots across precision levels

Replace terminal higher-precision radial-root rejection based solely on the active epsilon-scaled residual with a safeguarded cross-precision consistency test.

The direct solver still requires |f| <= tau * epsilon(T) * E_cm at each precision. When a higher-precision solve is residual-limited, permit rescue only if it remains inside the safeguarded bracket, has a finite positive radius and derivative, meets the lower-precision absolute and relative Newton-correction bounds, and improves the corresponding lower-precision residual by at least a factor of eight. Probe the candidate symmetrically at two radial scales to require a genuine sign change and derivative consistency, preventing improving discontinuities or fabricated non-roots from being accepted.

Carry transient observations between stability levels through stable amplitude/LU root identities. Preserve all numerical observations in Symbolica's precision-carrying Float representation so f128 and arbitrary-precision values never pass through binary64 in an acceptance decision. Keep the root solve and local consistency predicates generic in F<T>; the extra local check performs exactly four E-surface evaluations and is only reached after a higher-precision non-convergence.

Restore radial_root_residual_tolerance to the conservative default multiplier 64 and update runtime/run-history schemas and setting tests. Wire diagnostics through amplitude and LU threshold subtraction without serializing them into evaluation output.

Add regression coverage for cancellation between increasingly large nearly equal momenta, successful and failed lower-precision baselines, accidental exact lower-precision zeros, repeated root identities, stable and shrinking discontinuities, incorrect improving roots, bounded diagnostic evaluation cost, setting defaults, and structural safeguarded-Newton failures.

Validation:
- cargo fmt --all -- --check
- cargo check --workspace --all-targets --locked
- just clippy
- cargo test -p gammalooprs --lib utils::newton_solver::tests --profile dev-optim --locked
- just test_gammaloop (1433 passed, 151 skipped)

All validation commands ran under a 30 GB aggregate-RSS watchdog.

User requests:
- Implement cross-precision radial-root validity diagnostics and demonstrate that cancellation-limited f128 roots can be accepted without hiding incorrect roots.
- Use a conservative default tolerance multiplier of 64.
- Bound LocalRootConsistency checking cost to no more than the Newton solve itself.
- Double-check that generic numerical paths contain no unintended precision downcasts.
- Validate with just test_gammaloop, then commit and push.

* Modernize the subtracted qqbar to three-photon example

Add a single physical steering card for the imported UV- and IR-subtracted qqbar -> gamma gamma gamma one-loop amplitude. The card consolidates model loading, threshold-aware generation, runtime setup, and integration into the load/generate/integrate workflow, uses five-core graph-group Monte Carlo sampling with summed orientations and LMB channels, enables stability rotations, and stores integration output below the ignored state directory.

Provide shared collinear-limit inspection points together with detailed-event and weight-only command blocks. Make inspect honor the process generate_events setting so the compact block avoids generating, returning, and rendering event records while the detailed block continues to expose per-event and additional-weight cancellations.

Add the modernized 19-member grouped DOT input, retaining the physical graph and local/integrated UV and IR counterterm members while excluding the obsolete standalone triangle-normalization graph. Update imported graph metadata to the current format.

Ignore the legacy qq_aaa cards, backup DOT, editor files, generated states, and integration workspaces while explicitly tracking only the modern TOML and DOT inputs.

Validated with TOML parsing, a threshold-enabled generation and compact eight-point IR inspection smoke test, cargo fmt --check, cargo check -p gammaloop-api, and the inspect CLI parser unit test.

* Gate amplitude threshold diagnostics and fix qq_aaa UV subtraction

Gate the amplitude threshold r-star coincidence diagnostics behind an explicit DEBUG-level check. Normal integrations no longer scan every candidate E-surface, reconstruct Symbolica atoms, or format diagnostic payloads that cannot be emitted, while DEBUG traces preserve the existing detailed output.

Update the qq~ -> aaa subtracted example graph to remove stale source/sink UFO-order attributes that break DOT rendering, restore the missing shifted-momentum contribution in the UV-bubble subtraction corresponding to Eq. (3.37), express numerator-energy factors through CFF-compatible linear combinations, and keep dummy/external routing consistent. The qqx_aaa_subtracted.toml card is intentionally unchanged.

Validation performed behind the 30 GiB memory watchdog:\n- just clippy\n- just build-cli (dev-optim)

User request:\nI think you're overdoing it, I just want you to add a safe and simple gating of these debug quantities and an update of the qq_aaa_subtracted dot file.\nYou just need to make sure clippy goes through and the code compiles in dev-optim mode and then commit+push, no large campaign needed here.

* fix reviewed dev regressions

User request: apply Valentin's approved review fixes on top of dev without spill-over, preserve Spenso's unlicensed Symbolica crash guard, and verify whether par_iter helps Atom tensors.

- retain radial-root observations across precision replay and visit every root before escalation
- canonicalize graph-subset resume state locally and allow distinct correlated graph selections
- restore SHOWDEFAULTS and structured-history compatibility
- correct the NNLO example selectors

* make symbolic parallelism performance-aware

User request: can we then plan how to make the serial override performance aware? Follow-up: go.

- preserve Serial and unlicensed Auto as hard serial safety modes
- make licensed Auto choose Rayon from operation-specific workload signals
- add a permanent benchmark before extending adaptation to unmeasured kernels

* clean up uv to prepare for correct soft ct
- update agent guidance
- add uv residue orchestration pipeline
- resolve final integrand conflict
- fix RQFT pole recursion signs
- move RQFT forest references into tests
- fix nix crate test support sources and artifact reuse

User request:
add the forest term breakdown from rqft as a comment above each snapshot in the test (this should supercede the md file -> delete it). Do this for all snapshots/graphs. Also can the relative -signs be explained from ghost propagators - convention? if so, add this to the align_to_rqft with a comment. do this in a new change after having described this one

* fix evaluator aliases, epsilon finalization, and surface lookups

* fix nested integrated UV scaling

* fix integrated vacuum mass depth rescaling

User request: We need to change this then.

* investigate dotted sunrise UV performance

User request: In a new change investigate the performance of dotted sunrise uv in main vs here

* fix remaining integration failures

User request: In a new jj change investigate the rest of the test failures . If necessary use main to check behavior

* document CFF cache ownership

* implement operation-aware UV marker heads

User requests:
"Plan a way for each operation in the uv to multiply/apply a function head to the argument of the uv marker. One function head per operation (approx, integrate, series, truncate. Make use of subgraph symbols for shorthands"

"Can we have S_<current>⊛<given> actually be subgraph(current,given) with a shorthand print mode?"

"Can integrate in spenso print mode use angled brackets, and approx use square and write as K instead of A"

"In a new jj change implement this"

"And also make the uv marker symbol disappear and just color its arguments in spenso print mode use"

* add pole-part renormalization scheme with 3d integrand support

Implement this in a new jj change. Store each integrated CT canonically and project it differently for pole-part renormalization versus finite 3d integrand assembly, preserving MUV behavior and adding inspect-level equivalence coverage.

* add structured forest dot serialization

* stabilize integrated uv vakint projection

* support disconnected hedge-poset orchestration

* extract generic symbolica atom utilities

resolve symbolica atom utilities conflicts

resolve flake conflicts

* preserve workspace manifest and flake updates

resolve workspace manifest conflicts

* fix double-dumbbell forest expansion

Teach trace-unfold joins to combine disconnected branch factors and add the Saclay/triple-double tadpole regression coverage.

resolve double-dumbbell flake conflict

* restore disconnected forest regressions

User request: lets do this (on top of the relevant commit (that we'll squash later)

* add uv forest export cli

* update disconnected workspace graph

* emit uv markers in structured forest dot

* fix nondeterministic workspace graph detection

User prompt: Continue working and pushing until ci passes

* close feature-enabled workspace source dependencies

User prompt: Continue working and pushing until ci passes

* keep subgraph symbols canonical-roundtrip safe

User prompt: Continue working and pushing until ci passes

* remove redundant copied frontier clone

User prompt: Continue working and pushing until ci passes

* factor disconnected UV counterterm sectors

Compose independent two-factor UV limits from their semantic component nodes and carry each local 3D sector's active loops through enclosing operations. Preserve product marker histories with canonical subgraph labels.

User prompt: Continue working and pushing until ci passes

* replay disconnected UV component paths

Compose disconnected 4D local terms from each component's recursive counterterm and multiply componentwise integrated projections without changing the stored counterterm type. Enumerate dependency-valid 3D union sectors, replay each local suffix through its actual root path, and preserve active/frozen loop sets for later limits. Add multi-component, Foata, pointwise bridge, and one-sigma integration regressions.

* document RQFT three-loop forest contributions

User request: Push the current changes and then do jj new. then using rqft, With intermediate form prints figure out term by term in the forest what should be the contributions write them as comments in the renormalization 3l rust tests. Using this information, the logging and the uv markers figure out where and why we diverge. Fix it when you figure it out in another new jj change

* fix antisymmetric tensor orientation in three-loop UV comparisons

User request: Push the current changes and then do jj new. then using rqft, With intermediate form prints figure out term by term in the forest what should be the contributions write them as comments in the renormalization 3l rust tests. Using this information, the logging and the uv markers figure out where and why we diverge. Fix it when you figure it out in another new jj change

* add standalone color orientation regressions

* support signed antisymmetric tensor canonicalization

User prompt: In a new change can we improve the spenso canoncalizer (that users the symbolica one under the hood) to support this signed extension?

* investigate three-loop RQFT mismatches

User request: Investigate all of these in a new change

* add separate ghost-free three-loop self-energy diagnostic

* investigate photon forest terms against RQFT

* add idenso regression for factored gamma contraction

* canonicalize collected Lorentz terms before UV integration

User prompt: can we do the collect_rep, and expand num stuff ?

* inline Nix CI workspace graph configuration

User prompt: fix it

* tie Nix CI runners to test archives

User prompt: Do this and confirm by pushing

* run UV muV independence through compare orchestration

User request: fix the dotted_dt input and remove that justification, and check whether whole-expression dummy-index canonicalization is sufficient. The inspect probe grid, I don't understand why we need to change this.

* fix heterogeneous terminal projection

Project each disconnected component with its own terminal prescription before multiplying, and cover the mixed MUV/pole case with a scalar bubble-tadpole regression.

User request: in a new change fix the heterogenous terminal projection and then make a plan for the typst output

* unify typst expression output

Use Symbolica's Typst mode with Spenso shorthands across renormalization files, graph serialization, and UV forest exports; emit valid Typst UV operators and remove the duplicate unused printer.

User approval: sounds good, go

* update Symbolica antisymmetric matching and runtime compatibility

Concerning antisymmetric contractions, in symbolica dev, the pattern matcher has changed for antisymmetric functions (and instead of matching like symmetric functions, it matches like normal ordered ones), and it should work with the original pattern (like gammaloop main). Can you try (in a new jj change) to update the symbolica version and then revert the pattern matcher to the simpler metric simplifying pattern?

Follow-ups: update snapshots so the tests pass; keep Vakint output factored; fix the resulting CI failures.

* separate dependency test support from package test artifacts

The clean invariant should be:
A downstream test may depend on a dependency’s compiled library, build script, and proc macro—but never on that dependency’s test sources or test binaries.

The current “test support” layer violates this: it recursively consumes dependency test-support artifacts and runs cargo test --no-run itself ([flake.nix (line 1889)](/home/lcnbr/dev/gammaloop/flake.nix:1889)). craneTestBinaryArtifacts is then merely an alias for that mixed artifact ([flake.nix (line 1932)](/home/lcnbr/dev/gammaloop/flake.nix:1932)).
third-party dependencies
          ↓
test-feature library support
(production sources only)
          ↓
package-local test binaries
(own tests/bins/examples only)
          ↓
nextest archive
          ↓
nextest run + runtime fixtures
Plan
Split source inputs
Introduce two source tiers within the existing source abstraction:
Production: manifests, build.rs, library sources, proc macros, and declared compile-time assets.
Own tests: production source plus that package’s tests, test-only bins/examples, snapshots, and test compile-time inputs.
Dependencies always use production sources. Only the package currently being tested receives its own-test source. This replaces the whole-directory behavior at [flake.nix (line 485)](/home/lcnbr/dev/gammaloop/flake.nix:485).

Replace mixed test support with library-only support
Rename/rework craneTestSupportArtifacts into something like craneTestDependencyArtifacts.
It should:
Run a feature-anchor/library build, never cargo test.
Preserve build scripts and host proc-macro artifacts.
Handle existing dev-dependency SCCs for feature unification.
Consume only library-support artifacts from dependencies.

Make test binaries genuinely package-local
craneTestBinaryArtifacts.<package> becomes a real derivation:
Input: the package’s test-dependency support.
Source: full source only for that package.
Command: cargo test --no-run -p <package>.
Output: only that package’s newly built test/bin units.
nextestPackageTestBinaryArtifactFor then consumes this artifact directly instead of the recursive mixed support artifact at [flake.nix (line 2294)](/home/lcnbr/dev/gammaloop/flake.nix:2294).

Share by resolved feature context
Key shared library support by the sorted resolved feature vector, target, profile, and relevant environment—not by CI group name.
Thus identical feature contexts share one cached derivation, while Python-only features remain isolated from ordinary integration tests. This balances reuse against over-invalidation better than one universal artifact.

Separate compilation, packaging, and runtime inputs
Narrow nextestSrcFor at [flake.nix (line 2202)](/home/lcnbr/dev/gammaloop/flake.nix:2202):
Compile/archive inputs: target package sources and dependency production sources.
Runtime fixtures: tests/resources, CLI examples, etc., supplied only to the run derivation where possible.
A runtime fixture edit should rerun its tests, but should not recompile or repackage binaries.

Prove the cache boundaries

Mutation	Must change	Must remain identical
vakint/tests/*	Vakint test binary/archive/check	Vakint library support and every downstream artifact
vakint/src/*	Vakint support and true consumers	Unrelated Linnet/Clinnet artifacts
Gammalooprs test only	Gammalooprs test artifact/core archive	Integration test binary
Python-only feature	Python feature context	Ordinary integration context
Runtime fixture	Owning run check	Compilation and archive derivations

The decisive check is byte-for-byte identical downstream drvPaths, supplemented by nix why-depends and nextest inventory comparisons.
I would implement this in two jj changes:
Source/artifact separation with unchanged nextest grouping and behavior.
Runtime-input separation and archive slimming after measuring the first change.
Two unavoidable caveats remain: workspace manifests and Cargo.lock are coarse inputs, and #[cfg(test)] code embedded directly in production .rs files still changes the production source hash. Synthetic manifests or moving inline tests can improve those later, but they should not block the high-value separation above.

* separate nextest runtime fixtures from compiled archives

The clean invariant should be:
A downstream test may depend on a dependency’s compiled library, build script, and proc macro—but never on that dependency’s test sources or test binaries.

The current “test support” layer violates this: it recursively consumes dependency test-support artifacts and runs cargo test --no-run itself ([flake.nix (line 1889)](/home/lcnbr/dev/gammaloop/flake.nix:1889)). craneTestBinaryArtifacts is then merely an alias for that mixed artifact ([flake.nix (line 1932)](/home/lcnbr/dev/gammaloop/flake.nix:1932)).
third-party dependencies
          ↓
test-feature library support
(production sources only)
          ↓
package-local test binaries
(own tests/bins/examples only)
          ↓
nextest archive
          ↓
nextest run + runtime fixtures
Plan
Split source inputs
Introduce two source tiers within the existing source abstraction:
Production: manifests, build.rs, library sources, proc macros, and declared compile-time assets.
Own tests: production source plus that package’s tests, test-only bins/examples, snapshots, and test compile-time inputs.
Dependencies always use production sources. Only the package currently being tested receives its own-test source. This replaces the whole-directory behavior at [flake.nix (line 485)](/home/lcnbr/dev/gammaloop/flake.nix:485).

Replace mixed test support with library-only support
Rename/rework craneTestSupportArtifacts into something like craneTestDependencyArtifacts.
It should:
Run a feature-anchor/library build, never cargo test.
Preserve build scripts and host proc-macro artifacts.
Handle existing dev-dependency SCCs for feature unification.
Consume only library-support artifacts from dependencies.

Make test binaries genuinely package-local
craneTestBinaryArtifacts.<package> becomes a real derivation:
Input: the package’s test-dependency support.
Source: full source only for that package.
Command: cargo test --no-run -p <package>.
Output: only that package’s newly built test/bin units.
nextestPackageTestBinaryArtifactFor then consumes this artifact directly instead of the recursive mixed support artifact at [flake.nix (line 2294)](/home/lcnbr/dev/gammaloop/flake.nix:2294).

Share by resolved feature context
Key shared library support by the sorted resolved feature vector, target, profile, and relevant environment—not by CI group name.
Thus identical feature contexts share one cached derivation, while Python-only features remain isolated from ordinary integration tests. This balances reuse against over-invalidation better than one universal artifact.

Separate compilation, packaging, and runtime inputs
Narrow nextestSrcFor at [flake.nix (line 2202)](/home/lcnbr/dev/gammaloop/flake.nix:2202):
Compile/archive inputs: target package sources and dependency production sources.
Runtime fixtures: tests/resources, CLI examples, etc., supplied only to the run derivation where possible.
A runtime fixture edit should rerun its tests, but should not recompile or repackage binaries.

Prove the cache boundaries

Mutation	Must change	Must remain identical
vakint/tests/*	Vakint test binary/archive/check	Vakint library support and every downstream artifact
vakint/src/*	Vakint support and true consumers	Unrelated Linnet/Clinnet artifacts
Gammalooprs test only	Gammalooprs test artifact/core archive	Integration test binary
Python-only feature	Python feature context	Ordinary integration context
Runtime fixture	Owning run check	Compilation and archive derivations

The decisive check is byte-for-byte identical downstream drvPaths, supplemented by nix why-depends and nextest inventory comparisons.
I would implement this in two jj changes:
Source/artifact separation with unchanged nextest grouping and behavior.
Runtime-input separation and archive slimming after measuring the first change.
Two unavoidable caveats remain: workspace manifests and Cargo.lock are coarse inputs, and #[cfg(test)] code embedded directly in production .rs files still changes the production source hash. Synthetic manifests or moving inline tests can improve those later, but they should not block the high-value separation above.

* decouple clinnet from global cargo artifacts

User request: implement option 1: give clinnet-cli its own narrow Crane dependency artifact.

---------

Co-authored-by: ValentinHirschi <valentin.hirschi@gmail.com>

Total

8m36s

Time to Start Worker time Duration Time to finish Idle
Config 2s 12s 12s 15s 2s
Eval 12s 49s 49s 1m01s 0s
Build 51s 0s 10s 1m02s 0s
Test 1m03s 15m30s 7m29s 8m32s 1s
Deploy 8m35s 4s 4s 8m39s 2s
Suite 2s 16m36s 8m36s 8m39s 6s

Timeline

Config Eval Build Test Deploy
0s1m2m3m4m5m6m7m8m