Merge origin/master into suns-never-green + consumable-ai merge (docs only)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-16 20:53:39 +02:00
commit da6fe0334e

View file

@ -89,6 +89,9 @@ All read at c6519383 in the detached worktree `C:\aeth-wt\ag2-docs` on 2026-10-1
- **B49. Stardust against the nebula march** (probe 2026-10-16 by imagination-ag4-stardust-order at 6b6e7c7c, Unity 6000.3.24f1 batchmode D3D11, ARPG.unity Main Camera, deferred HDR; every camera MonoBehaviour disabled, an [ImageEffectOpaque, ExecuteAlways] snapshot added that copies its source and _CameraDepthTexture; an Unlit/Color quad 50 u ahead drawn by a CommandBuffer at one event per render; log in the session scratchpad imagination-ag4-stardust-order/probe2.log). The nebula is VolumeCloudRenderer, an [ImageEffectOpaque] OnRenderImage: it marches to _CameraDepthTexture and composites mcol*(1-a)+cloud (CloudShader.shader:161, :361). Seen by the opaque effect (so fogged): BeforeLighting, AfterLighting, BeforeImageEffectsOpaque. Drawn but after it (so on top of the fog): AfterImageEffectsOpaque, BeforeForwardAlpha, which is where 1973b6d2 put the dust. Not run with no forward-opaque object or skybox: BeforeForwardOpaque, AfterForwardOpaque, BeforeSkybox, AfterSkybox. BeforeImageEffectsOpaque ran with every image effect disabled. Only BeforeGBuffer and AfterGBuffer depth writes reach _CameraDepthTexture (a deferred camera copies it from the G-buffer depth), and a single-target colour draw there lands in albedo and is unlit. So the dust has never been in the depth the march reads: before the cut (a queue-2000 renderer drawn forward after lighting) the march ran past it and laid the whole ray's fog over it, as it will again at BeforeImageEffectsOpaque. Dust in front of a cloud is fogged as if behind it; per-particle depth occlusion would need a G-buffer pass writing emission to the lighting target.
- **B50. Pockets: drawn extent and nesting, flown against ruled** (`pockets.py`, imagination-ag4-children-reach scratchpad, 2026-10-16, over the B35 bodies.csv, 188 of 1500 zones; it reuses r3's `probe4.py` law and `replace.py` placement, so it is a numpy port, not a Unity render). For each body with a body parent, along the line to the parent (the pocket's tight side): r_v is where its outermost closed contour at the minimap spacing (deepest body / 20, IsolinesUI.shader:178) crosses, r_s the saddle (its basin's edge), both in body radii 3 m^0.25. Flown at 6865af81 (C0: harmonic core, today's generator): planets r_v p50 2.0 (2.5 for planets with moons), 44% with no closed contour of their own; 4% of planets' children inside the drawn extent and 24% inside the basin (gas giants 22%/55%, suns with a body parent 26%/55%). Well-law alone (C1): planets r_v 5.5, no contour 23%; children inside 11%/33% (gas giants 39%/66%). Well-law plus children-within-reach's rules (C4): planets with moons r_v p50 6.5 (p10 2.0, p90 15.1); children inside the drawn extent 51% and inside the basin 91% (gas giants 65%/90%, suns 83%/91%); 32% of planets, mostly moonless, still draw no closed contour. Reading against the operator's flight (follow-up wells-read-as-pockets): "barely larger than themselves" is measured at C0 (about 2 body radii), and most of a planet's moons then sat outside its basin. Both rules move it; what remains (half of moons inside the basin but outside the outermost drawn contour, moonless planets with no contour) is contour spacing, grid-noise-presentation's. Her screenshot (session image 4.png) is the in-world view with orbit rings, not the minimap, so this is a proxy for what she saw.
- **B51. Binary members shear, and C4 merges most binaries** (`shear.py`, `stats.py`, same scratchpad and data). At 4fb5cb94 a binary member's period is its partner's own terms at the chord (WellTree.PullAround), so unequal members on one ring get unequal periods: of 1163 generated binaries 99% have unequal periods (ratio p10/50/90 1.016/1.091/1.236); started opposite, they meet after p50 665 s (p10 171 s), 47% within 10 minutes of play. The log-law equilibrium of a pair is two radii, r_i proportional to c_partner (rosette-relative-equilibria.md section 1), which WellTree's one-radius ring group (RingOf, RingWindow) cannot express. Under C4 (replace.py, all 1500 zones) 905 of 1155 non-root binaries cannot keep their members outside each other's Roche limit inside their node's reach and become one body; 9026 massive nodes and 1658 of 3134 belts fold into their parents; non-root binaries keep no circumbinary child (the bound 7.5 D_ring equals the window's top, D_node/6), and root rosettes keep none (7.5 x 0.375 Z exceeds 0.75 Z).
- **B52. Multi-root zones: three shapes for the zone's owner** (imagination-ag4-well-law-r3 scratchpad, 2026-10-16: `ImagWellDump.cs` run on Yggdrasil at 4fb5cb94 (job jE) dumps every orbit of 40 production entrance zones, seeds 1-40, with masses, t = 0 positions and belt extents; `welltree.py` ports WellTree's BuildReaches and EmitTerms in float64; `shapes.py`, `overlap.py`). 32 of the 40 zones have 2-6 massive parentless roots, one per occupied area (ZoneGenerator 93). Metrics: far = |F| r / c(M_zone) at 10 Pack.Radius, r from the origin; foreign = |force at a child's rail point with its own subtree removed, less its parent body's Plummer pull| / that pull, for children of bodies, split between the heaviest root's subzone and the others; depth = deepest drawn potential over the bodies / one body of M_zone at the origin (Soul's metric); plain = share of 60 random points inside 0.75 R where |F| < 1e-3 c(M)/R. *Today* (every root its own global term): far p50 2.21, max 4.16; foreign heavy/light p50 0.49/0.28; depth p50 1.10; plain 0. *Isolated subzones* (one zone node at the roots' barycentre owns the only global term, c(M_zone)[U_global - U(A, 1.5 A)] with A = max over roots of distance to the node + reach; each root's reach max(0.5 x nearest-root distance, 1.5 x support)): far 1.000 (0.997-1.005 from the origin, exact from the barycentre); foreign 0.41/0.17; depth p50 0.82, max 1.42; plain p50 8%, max 28%. *Nested under the heaviest root* (the other roots become its children): far 0.92-1.00 from the origin, exact from the heavy root; foreign 0.41/0.20; depth 0.97; plain 0; every light root then sits fixed on the heavy root's slope. *Superposed inside* (each root reaches past the pack and fades where the zone term rises): inside the pack it is today's field, foreign and depth as today, far exact. Under isolated subzones 73 of 130 roots take the 1.5 B floor rather than half the nearest-root distance, and 210 of 490 ordered root pairs have one root's reach entering the other's support: today's generator gives roots families wider than their areas. A sits at p50 1.43, max 2.70 Pack.Radius. Most of the foreign share in both subzone kinds is siblings and children outside their reach (today's generator), which children-within-reach owns.
- **B53. Belt extent** (same dump, `belts.py`, 155 belts under bodies in 40 zones). With L_F read from the belt orbit's Distance (4fb5cb94), the parent's own pull at a belt's outermost asteroid over its body's Plummer pull is at minimum 0.012 (p01 0.938, 8 belts under 0.99); with L_F read from the outermost asteroid it is 1.000 for every belt. The asteroid spread is the generator's (ZoneGenerator 150: Distance + u (v - 1/2) AsteroidBeltWidth(D)): 42 of 155 belts reach inside their parent's Roche limit and 1 below distance 0.
- **B54. The series threshold, measured** (`threshold.py` on Soul's `band_check.py`: float32 port against 40-digit mpmath quadrature, five (a, b) shapes, 15 radii each). Worst error per unit strength with the series from tau 0.4 (40 terms): 1.0e-6 overall; 3.1e-7 at tau 0.05, 6.1e-7 at 0.3, 4.7e-7 at 0.39 (closed), 9.7e-7 at 0.41, 1.0e-6 at 0.43, 6.5e-7 at 0.6, 4.9e-7 at 1, 2.3e-7 at 2.5, 6.0e-8 at 10. From 0.5: 1.04e-6; 0.6: 1.45e-6; 0.7: 2.63e-6; 1 (4fb5cb94): 1.01e-5 (at tau 1). The closed form is float32-clean only to about tau 0.45 (9.7e-7) and worsens from there (1.5e-6 at 0.6, 1.0e-5 at 1).
## Model page
@ -128,6 +131,10 @@ Cells not filled, plainly: whether a per-body multiplier on c or the core is eve
- Why one field quad and not the per-body Gravity Well quads with the new law: B30. The per-body quads also cost a GameObject, a material instance and a scale per body, and a quad per body has to cover every camera's view because log tails have no support radius.
- Why a period is derived from `GravityField.Acceleration` rather than written as 2πd/sqrt(c): the formula is the tail law spelled a second time and is wrong inside the core (it would run a child faster than any free orbit there); T = 2π·sqrt(d/a) reads the one law, so the core, and any later change to the law, arrive in the rails with no edit (B35's 234 in-core children get a finite solid-body period).
- Why the asteroid periods live on the belt: Pose and BeltTargets must divide by the same float (BeltTargets.cs:62); one array computed at build is one owner, where two calls to the same function are two spellings that only agree by care.
- Why one zone node owns the zone's far field (well-law r3): the conserving property is one global term of the total mass, and a tree with several roots has several. Hierarchical N-body methods put the same fact in structure: Barnes-Hut (1986) and the fast multipole method (Greengard and Rokhlin 1987) keep one root cell holding everything, whose far field is the monopole of the total mass at its centre of mass. So the node sits at the roots' barycentre; it is not an orbit, has no body and no ring group, and gives no rail (roots are stationary, period +inf, so parent-only rails are untouched). A zone with one massive root needs no node: that root keeps its infinite reach and nothing about single-root zones changes.
- Why nesting the light roots under the heaviest is rejected (B52): roots are stationary, so a light sun fixed on the heavy sun's slope sits in a field nothing balances; a ship parked by it drifts toward the heavy sun while the sun's planets keep their rails, which is the coasting-orbit mismatch `tame-tails-parent-only-rails` ruled out. Patched conics (spheres of influence, as KSP flies them) are the prior art for the alternative: each region owned by one body. Isolated subzones are that reading for stationary roots; superposed-inside keeps today's superposition of fixed masses. Which one the operator flies is question `multi-root-zone-shape`.
- Why a belt's extent is the well tree's input and not the placement's alone: "inside L_F a node pulls as its body alone" is the tree's guarantee about every rail round the node, and a belt is a family of rails out to its outermost asteroid (B53). The tree reads that extent; children-within-reach decides where belts go and how wide, and must keep their inner edge outside the Roche margin.
- Why the series threshold is a GravityField constant emitted into the template: B54 sets it at 0.4 by measurement, and a literal `1` in both C# and HLSL is the second spelling `gravity-law-one-spelling` already names.
- A constraint for pseudospace, not solved here: a push with curl (B11) has no height, so under `grid-shows-how-you-move` it either never moves ships, or is drawn by another channel, or is restricted to its gradient part.
## Cut sequence
@ -135,7 +142,7 @@ Cells not filled, plainly: whether a per-body multiplier on c or the core is eve
Mapped and admitted (2026-10-14, base 11b2d7ad): `aetheria-gravity:cut_spec:cut-gravity-subtract.r2` and its sibling `aetheria-gravity:cut_spec:cut-orbits-placed-at-build.r1`, both merged at 5dd1f6b7. Mapped and admitted (2026-10-14, base 5dd1f6b7): `aetheria-gravity:cut_spec:cut-potential-owner.r3` (rebased on 3f5cef68 on 2026-10-15, after rulings `funnel-kept-until-flown` and `core-inside-roche-curve`), one Hands pass; it carries follow-ups `deep-orbit-placement-test` and `gravity-subtract-test-residuals`. Between it and grid-lowering the drawn grid lags (B23). The operator will fly the funnel before ruling on it again (`funnel-kept-until-flown`), so potential-owner and grid-lowering must both be on one playable branch before that flight; grid-lowering is stacked on potential-owner, not a sibling (B26), and its map is the next Imagination pass once potential-owner's report lands. Mapped and admitted (2026-10-15, base dd06f39d, stacked on potential-owner's head): `aetheria-gravity:cut_spec:cut-grid-lowering.r1`, one Hands pass, Starfire-verified; on its branch the drawn grid is the field (B30) and the Sector Waves noise is off the grid until grid-noise-presentation. Mapped and admitted (2026-10-15, base 8f491fd3, stacked on grid-lowering's head): `aetheria-gravity:cut_spec:cut-fog-precision-and-jitter.r1`, the slope jitter (B32) and the patch's second gravity lowering (B33), one Hands pass. Mapped and admitted (2026-10-15, base 8f491fd3, a sibling of fog-precision-and-jitter on grid-lowering's head, disjoint files): `aetheria-gravity:cut_spec:cut-orbits-from-field.r1`, periods from the field (B35-B38), one Hands pass; it raises `aetheria-gravity:question:rails-enclosed-or-parent` and is written for the recommended parent-only option. Not yet mapped:
- **drawn-pose-at-drawn-time** (mapped and admitted 2026-10-15, base 09ec04a8: `aetheria-gravity:cut_spec:cut-drawn-pose-at-drawn-time.r1`, one Hands pass): `DrawAhead` owns every drawn pose at T = ExactTime + Lead (B39); closes item 3 of `fog-jitter-residuals`.
- **tail-taming** (ruling `tame-tails-parent-only-rails`, lean `tail-taming-lean-conserving-compact`): `aetheria-gravity:cut_spec:cut-well-law.r2` (the band law, B40-B43, B48; reach 1/2 D, series branch), runnable before question `tail-taming-law-r3` is answered; the generator rules go to children-within-reach once r3 sets the spacing.
- **tail-taming** (ruling `tame-tails-parent-only-rails`, lean `tail-taming-lean-conserving-compact`): `aetheria-gravity:cut_spec:cut-well-law.r2` (the band law, B40-B43, B48; reach 1/2 D, series branch), runnable before question `tail-taming-law-r3` is answered; the generator rules go to children-within-reach once r3 sets the spacing. Soul's s1 falsified it (multi-root far field, belt extent, unpinned fade start and ring edge, series threshold); the fix batch is `aetheria-gravity:cut_spec:cut-well-law.r3` (B52-B54), with the zone's shape between roots put to the operator as question `multi-root-zone-shape`. children-within-reach r2 needs a refresh after r3 lands (roots gain a finite reach, belts an extent).
- **potential-owner** (mapped, above): one ServerShared potential (c from an authored compressed curve G·m^p, authored core-radius curve, uniform-disc core, log tail, superposition, analytic gradient, no gate, global K in PlanetSettings, reference zero at the root's zone radius); every CPU force reader (Ship, floating bodies, clouds, mines) and `Zone.Flow`'s slope term read it; GetHeight = φ/K; deletes `GravityAcceleration`, `GravityReferenceRate`, `GetNormal` as a force source, the PowerPulse well and `GravityDepthExponent`; field strength per field-strength-ruled. Waits on both admitted cuts. May split into the potential and its readers if one Hands pass cannot hold both.
- **rosette-equilibria** (follow-up `rosette-generation-r3`, rulings `rosettes-artificial-derived-from-fields`, `rosettes-placed-in-equilibrium`, `rosettes-rare-and-huge`, `binaries-orbited-from-afar`): pairs and rosettes placed as relative equilibria under the band law, members on their own radii (a pair at r_i proportional to c_partner; twisted crowns for alternating rosettes), one spin for every member, so no ring shears (B51); WellTree's ring group accepts members on two radii; members always suns, rare and huge. Waits on children-within-reach (`cut-children-within-reach.r2`), which places rings as today's one radius.
- **grid-noise-presentation**: the Sector Waves noise (after grid-lowering on layer 10, drawn only into the nebula patch height) and fine-grid detail move to non-slope presentation (grid-gravity-only-ruled); it also owns the Main Menu's own Surface Displacement brushes (B29, follow-up `menu-grid-brushes`). Waits on grid-lowering.