Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
68cbbc4
docs(ecs): chart dual-category ECS architecture
Milky2018 Jul 15, 2026
11d42e8
docs(ecs): claim valtype capability research
Milky2018 Jul 15, 2026
201a6cf
docs(ecs): define table-batched value queries
Milky2018 Jul 15, 2026
ca8c064
docs(ecs): research valtype query enforcement
Milky2018 Jul 15, 2026
5db08f4
docs(ecs): record value-component language blocker
Milky2018 Jul 15, 2026
c5245d2
docs(ecs): abandon dual-category ECS redesign
Milky2018 Jul 15, 2026
b830786
feat(ecs): add bypass change detection writes
Milky2018 Jul 15, 2026
912742c
fix(visibility): preserve semantic change detection
Milky2018 Jul 15, 2026
0451a97
feat(visibility): add GPU culling producer
Milky2018 Jul 15, 2026
caee281
perf(camera): stream visible entities directly from queries
Milky2018 Jul 15, 2026
7ad33e3
feat(light): port shadow visibility producers
Milky2018 Jul 15, 2026
011260c
perf(visibility): remove blanket visibility producer
Milky2018 Jul 15, 2026
df70870
docs(issues): record visibility performance migration
Milky2018 Jul 15, 2026
4b44b2d
docs(issues): track dense ECS table storage refactor
Milky2018 Jul 15, 2026
d9c9ab6
test(ecs): lock table column length invariants
Milky2018 Jul 15, 2026
4d5b142
refactor(ecs): make component writers one-shot
Milky2018 Jul 15, 2026
342c86f
refactor(ecs): store table components in dense columns
Milky2018 Jul 15, 2026
985362e
fix(ecs): transfer component ownership through take
Milky2018 Jul 15, 2026
e385c30
perf(ecs): fetch required table values directly
Milky2018 Jul 15, 2026
776fefa
docs(issues): track new toolchain warnings
Milky2018 Jul 15, 2026
4a910a2
docs(issues): close dense ECS table refactor
Milky2018 Jul 15, 2026
5048af2
docs(ecs): track serial hot-path experiments
Milky2018 Jul 15, 2026
a1f7ba4
docs(ecs): reject query-cache lifetime experiment
Milky2018 Jul 15, 2026
f28e350
perf(ecs): separate value-only query reads
Milky2018 Jul 15, 2026
8b7b7b9
docs(ecs): reject persistent fetch-state experiment
Milky2018 Jul 15, 2026
324381b
perf(ecs): bind typed query columns per table
Milky2018 Jul 15, 2026
cf715d2
perf(ecs): stream dense query visitors
Milky2018 Jul 15, 2026
5affa92
docs(ecs): track generic valtype blocker
Milky2018 Jul 15, 2026
39fa5ac
docs(ecs): record zero-wrapper language limits
Milky2018 Jul 15, 2026
b2fdc77
docs(ecs): authorize table-batch experiment
Milky2018 Jul 15, 2026
3c1ed72
perf(ecs): add dense table batch traversal
Milky2018 Jul 15, 2026
91e8aef
fix(ecs): preserve batch component replacement semantics
Milky2018 Jul 15, 2026
209fb77
perf(visibility): batch reset view visibility
Milky2018 Jul 15, 2026
ca8e4f9
docs(ecs): track batch hotspot migrations
Milky2018 Jul 15, 2026
117fe00
docs(examples): track animated sprite visibility regression
Milky2018 Jul 15, 2026
93bb192
perf(visibility): batch newly hidden visibility updates
Milky2018 Jul 15, 2026
a6f4bb0
perf(camera): batch visible entity culling
Milky2018 Jul 15, 2026
c3c63bf
perf(sprite): batch sprite extraction
Milky2018 Jul 15, 2026
c5f2a98
fix(picking): align sprite picking query semantics
Milky2018 Jul 15, 2026
51bbb4f
perf(picking): batch sprite picking collection
Milky2018 Jul 15, 2026
0218316
fix(sprite): align 2d bounds update semantics
Milky2018 Jul 15, 2026
1cfac41
perf(sprite): batch 2d bounds scans
Milky2018 Jul 15, 2026
6b16cfe
fix(transform): align static optimization control
Milky2018 Jul 15, 2026
bbff485
perf(transform): batch dirty-tree trigger rows
Milky2018 Jul 15, 2026
1733238
fix(ecs): preserve row fallback for filtered batches
Milky2018 Jul 15, 2026
70d1773
fix(transform): align simple transform reads
Milky2018 Jul 15, 2026
318b0c3
perf(transform): batch simple transform sync
Milky2018 Jul 15, 2026
63fa528
fix(sprite): align computed slice reads
Milky2018 Jul 15, 2026
32fc13d
docs(sprite): track sprite slice render regression
Milky2018 Jul 15, 2026
8f7a3b9
perf(sprite): batch changed slice computation
Milky2018 Jul 15, 2026
9a3e80f
docs(ecs): close batch migration matrix
Milky2018 Jul 15, 2026
3443c14
docs(ecs): start demand-driven change tracking
Milky2018 Jul 15, 2026
67602b4
perf(ecs): remove changed message queues
Milky2018 Jul 15, 2026
f1e5e3a
perf(ecs): make change locations opt in
Milky2018 Jul 15, 2026
4a78dba
docs(ecs): start dense table registry experiment
Milky2018 Jul 15, 2026
8fae596
perf(ecs): index table storage by dense id
Milky2018 Jul 15, 2026
3628e4b
docs(ecs): start entity membership experiment
Milky2018 Jul 15, 2026
8557df1
perf(ecs): derive entity membership from archetypes
Milky2018 Jul 15, 2026
25c114d
docs(ecs): start query lease scope experiment
Milky2018 Jul 15, 2026
95ac854
fix(ecs): reject invalidated query cursors
Milky2018 Jul 15, 2026
e476d93
docs(ecs): reject query lease scope experiment
Milky2018 Jul 15, 2026
4884076
docs(ecs): start table move ownership experiment
Milky2018 Jul 15, 2026
11bfb71
docs: clarify focused moon test syntax
Milky2018 Jul 15, 2026
dfa801a
perf(ecs): unify shared table row moves
Milky2018 Jul 15, 2026
d2dfed4
docs(ecs): complete hot-path experiment matrix
Milky2018 Jul 15, 2026
e908fa6
fix(camera): restore Camera2d frustum updates
Milky2018 Jul 16, 2026
b75398c
docs(lighting): refresh alpha-mask reference
Milky2018 Jul 16, 2026
b663a62
fix(render): preserve source-owned cluster buffers
Milky2018 Jul 16, 2026
827ae5f
fix(pbr): grow bindless material slabs
Milky2018 Jul 16, 2026
a9fe964
docs(sprite): close sprite slice regression
Milky2018 Jul 16, 2026
05c34d3
docs(sprite): close delayed visibility regression
Milky2018 Jul 16, 2026
810989d
docs: clarify delayed physics captures
Milky2018 Jul 16, 2026
5c93349
fix(examples): align many animated sprites with Bevy
Milky2018 Jul 16, 2026
f5bbcf0
docs(perf): record animated sprites stage trace
Milky2018 Jul 17, 2026
613ae7a
perf(trace): split sprite bounds phases
Milky2018 Jul 17, 2026
20cb37d
docs(perf): record sprite bounds subtrace
Milky2018 Jul 17, 2026
748042a
docs(perf): compare sprite bounds with Bevy
Milky2018 Jul 17, 2026
cf9b4f6
docs(perf): localize animated sprite writes
Milky2018 Jul 17, 2026
6e17861
docs(perf): identify animated sprite performance bugs
Milky2018 Jul 17, 2026
4fba8ed
perf(ecs): add value component batch updates
Milky2018 Jul 17, 2026
e395d95
perf(time): store timers as value types
Milky2018 Jul 17, 2026
2352010
perf(sprite): update bounds through changed queries
Milky2018 Jul 17, 2026
c61a838
perf(camera): store Aabb as an inline value
Milky2018 Jul 17, 2026
f97cefb
perf(visibility): reset view state in a value batch
Milky2018 Jul 17, 2026
db38b1f
test(camera): preserve visibility reset state
Milky2018 Jul 17, 2026
bf74b15
perf(camera): cull bounds with inline scalar math
Milky2018 Jul 17, 2026
437969b
perf(visibility): reuse default render layers
Milky2018 Jul 17, 2026
2e0cdb5
docs(perf): record rejected entity access optimization
Milky2018 Jul 17, 2026
d9df769
perf(ecs): bind read-only table views
Milky2018 Jul 17, 2026
cad1901
perf(camera): update frusta through changed query
Milky2018 Jul 17, 2026
f8d0276
perf(pbr): extract changed materials through queries
Milky2018 Jul 17, 2026
b3535f0
perf(ecs): bind sparse row change metadata
Milky2018 Jul 17, 2026
79a693f
perf(asset): store texture atlas as inline value
Milky2018 Jul 17, 2026
94ec0b5
docs(perf): add matching Bevy frame trace
Milky2018 Jul 17, 2026
aca2fc7
perf(math): use native square root
Milky2018 Jul 17, 2026
55f714a
perf(camera): bind optional culling columns
Milky2018 Jul 17, 2026
fa26da0
perf(ecs): bind table entity views
Milky2018 Jul 17, 2026
cb2eb19
perf(ecs): bind filtered row values
Milky2018 Jul 17, 2026
fb5fa0f
docs(perf): reject sprite write view
Milky2018 Jul 17, 2026
f514cd1
perf(visibility): query changed propagation roots
Milky2018 Jul 17, 2026
08f0c16
perf(ecs): match dense change ticks as scalars
Milky2018 Jul 17, 2026
f6e6921
fix(packages): scope benchmark imports to tests
Milky2018 Jul 18, 2026
d481cbc
docs(api): record performance branch migrations
Milky2018 Jul 18, 2026
828e381
fix(visibility): make value updates migration-safe
Milky2018 Jul 18, 2026
8c29761
fix(picking): preserve affine sprite transforms
Milky2018 Jul 18, 2026
6f52724
chore(api): regenerate engine interfaces
Milky2018 Jul 18, 2026
59c8f15
fix(picking): restore standard Camera2d picking
Milky2018 Jul 18, 2026
952c536
fix(ecs): update component membership before despawn
Milky2018 Jul 18, 2026
12997f8
fix(ecs): preserve same-reference bypass ownership
Milky2018 Jul 18, 2026
8d371dc
fix(ecs): retain zero-column table rows
Milky2018 Jul 18, 2026
dddb8d9
fix(ecs): revoke escaped batch mutable views
Milky2018 Jul 18, 2026
b7eb509
perf(ecs): bound revocable batch views privately
Milky2018 Jul 18, 2026
d73f9d5
fix(ecs): authorize filtered batch rows
Milky2018 Jul 18, 2026
efca229
fix(camera): align Camera2d frustum scale
Milky2018 Jul 18, 2026
4d00228
fix(render): reset frame-local storage before render graph
Milky2018 Jul 19, 2026
3705071
Sync binary assets with pinned Bevy baseline
Milky2018 Jul 19, 2026
26c82f1
Gate Bevy resource mirrors against pinned hashes
Milky2018 Jul 19, 2026
5f1b48d
Qualify generic trait method dispatch
Milky2018 Jul 19, 2026
fae1dd6
Use explicit ECS trait key dispatch
Milky2018 Jul 19, 2026
a49d531
Upgrade window and wgpu typed surface integration
Milky2018 Jul 19, 2026
5bd9ef9
Release window surfaces before closing hosts
Milky2018 Jul 19, 2026
bb37894
Remove raw UInt64 window surface path
Milky2018 Jul 20, 2026
bc6e864
Refresh accepted 3D visual references
Milky2018 Jul 20, 2026
c211149
Fix dynamic directional shadow phase resolution
Milky2018 Jul 20, 2026
3d81d78
Upgrade WGSL dependencies to 0.16.0
Milky2018 Jul 20, 2026
617c8e4
Link ISS-405 to upstream moon_wgsl issue
Milky2018 Jul 20, 2026
1ef8e11
Upgrade WGSL dependencies to 0.17.0
Milky2018 Jul 21, 2026
c15e1bc
Upgrade moon_wesl to 0.17.0
Milky2018 Jul 21, 2026
07bcba2
Close resolved PBR compose blocker
Milky2018 Jul 21, 2026
781717a
Close fixed Moon test driver warning
Milky2018 Jul 21, 2026
b70ffb0
Revalidate macOS sanitizer blocker
Milky2018 Jul 21, 2026
a2aae58
Close resolved meshlet compiler blocker
Milky2018 Jul 21, 2026
118d02a
Refresh meshlet runtime blocker status
Milky2018 Jul 21, 2026
0c8d20d
Fix issue guide trailing whitespace
Milky2018 Jul 22, 2026
1fa202b
Replace moon_taffy with chicle
Milky2018 Jul 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ The role of this file is to describe common mistakes and confusion points that a
- `Milky2018/wgpu_mbt@0.14.2` and `Milky2018/window@0.5.1` provide the current macOS `NSView*` renderer integration path. Use `Instance::create_surface_macos_ns_view_u64` with `Window::content_view_handle()` data instead of reintroducing project-local `CAMetalLayer` attach stubs or unsafe casts. Use `RenderPassDescBuilder::set_color_attachment_resolve_target` for MSAA color resolve attachments instead of project-local render-pass descriptor native stubs.
- When `moon test` fails with a tcc framework lookup error, rerun the same test with `--release`.
- Long `moon run` commands, especially native release builds and examples that compile large generated C files, may spend several minutes in clang/link/executable generation. Do not treat the long wait as a failure or switch debugging strategy just to avoid waiting; keep polling until the command naturally completes or produces a real error.
- On current MoonBit toolchains, `moon test -f` is the short form of `--filter`, not a test filename selector. Pass one test file as a positional path (for example, `moon test ecs/foo_test.mbt -f 'test name'`) and use only one filter flag.
- On newer MoonBit toolchains, a repository-wide `moon fmt` can migrate legacy `options("is-main": true)` entries to `pkgtype(kind: "executable")` and regenerate hundreds of package/interface files. For surgical changes, inspect `git status` immediately afterward and exclude unrelated migration churn from the task.
- Use this fixed native screenshot command shape for visual parity captures, for example:
`MGSTUDIO_PARITY_CAPTURE_DELAY_FRAMES=90 MGSTUDIO_PARITY_RUN_TIMEOUT_SECONDS=240 mgstudio-engine/scripts/p0_visual_capture_native.sh examples/2d/bloom_2d /tmp/mgstudio_iss025_camera_render_graph_bloom_2d.png`.
- A fixed-frame capture represents simulated time, not the wall-clock age of a checked-in reference. For physics-heavy examples such as `examples/3d/despawn3`, frame 90 at the default 16,667 microseconds is only about 1.5 seconds and should not be compared with a later settled-pile reference. If an exact delayed frame is required, set `MGSTUDIO_PARITY_CAPTURE_DISABLE_RETRY=1` and inspect `capture_delay_frames_used` in the generated metadata; otherwise a timeout retry can replace the requested output with a fresh-process frame-1 capture. A larger `MGSTUDIO_PARITY_FIXED_FRAME_TIME_US` can validate later fixed-update state with fewer expensive render frames.
- When an example runs correctly for the first time, save a reference screenshot in that example's source directory. Future agents should compare against that checked-in local reference before deciding that the example still renders correctly.
- Do not infer Bevy parity from a visually plausible example alone. The `examples/3d/motion_blur` audit showed that a scene can render and respond to input while still diverging from Bevy in ECS shape and data flow: Bevy used a `Text` root with `TextSpan` children and `TextUiWriter`, while mgstudio had been replacing one whole `Text` value every frame. For render/PBR/mesh/text/UI work, verify source-owner structure, component/resource ownership, schedule placement, dirty/change tracking, example behavior, and visual/performance gates before raising completion scores.
- If a bug appears in one feature area, check adjacent Bevy boundaries before assigning ownership. Input symptoms in `motion_blur` crossed window/AppKit event-loop timing, ECS schedule entry, UI text updates, and PBR postprocess state; treating the first visible subsystem as the root cause is usually wrong.
2 changes: 1 addition & 1 deletion CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ _Avoid_: committed Bevy patch, permanent baseline fork
> **Dev:** "Should bridge packages own behavior just because code lives there?"
> **Domain expert:** "No — **Runtime Owner Semantics** stays with the **Bevy Source Owner**; bridges only keep the port buildable and traceable."
>
> **Dev:** "If `moon_taffy` lacks a Bevy-required layout capability, is that a mgstudio parity gap?"
> **Dev:** "If `chicle` lacks a Bevy-required layout capability, is that a mgstudio parity gap?"
> **Domain expert:** "No — that is an **External Blocker** and should be tracked so the community can build the missing dependency capability."
>
> **Dev:** "If MoonBit cannot express the typed system parameter shape Bevy uses, can we encode the state as JSON?"
Expand Down
220 changes: 220 additions & 0 deletions docs/ECS_PERFORMANCE_API_MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
# ECS Performance Branch Public API Migration

This document records the source-breaking public API changes retained by the
ECS and render performance work tracked by `ISS-442`, `ISS-444`, `ISS-456`,
`ISS-461`, and `ISS-463`.

These changes are intentional, but they are not source compatible. The
generated interfaces expose struct fields, struct mutability, return types,
error variants, and generic bounds as public API. Downstream code that used
those details must be migrated before updating to this branch.

The audit compares this branch against its `main` merge base,
`df70870662fe5fb4ad151098fe6edd329431838b`.

## Value-Type Semantics

`Duration`, `Stopwatch`, `TimerMode`, `Timer`, `TextureAtlas`, `Aabb`, `Sphere`,
`InheritedVisibility`, and `ViewVisibility` are now MoonBit value types. Copies
no longer share object identity. Value updates return replacement values that
the caller must store.

MoonBit value types cannot contain the reference-typed fields used by the old
representations. The flattened fields are an implementation detail; downstream
code should use constructors and methods instead of depending on the new scalar
layout.

## Time

`Stopwatch` previously exported `elapsed : Duration`; it now stores
`elapsed_nanos : Int64`. `Timer` previously exported `stopwatch`, `duration`,
and `mode`; those fields are now flattened scalar state.

| Previous source | Replacement |
| --- | --- |
| `stopwatch.elapsed` | `stopwatch.elapsed()` |
| `Stopwatch::{ elapsed, paused: false }` | `Stopwatch::new().set_elapsed(elapsed)` |
| `Stopwatch::{ elapsed, paused: true }` | `Stopwatch::new().set_elapsed(elapsed).pause()` |
| `timer.stopwatch.elapsed()` | `timer.elapsed()` |
| `timer.stopwatch.is_paused()` | `timer.is_paused()` |
| `timer.duration` | `timer.duration()` |
| `timer.mode` | `timer.mode()` |
| `Timer::{ stopwatch, duration, mode, .. }` | Start with `Timer::new(duration, mode)`, then apply `set_elapsed`, `pause`, `finish`, or `tick` as required |

There is no supported replacement for constructing arbitrary inconsistent
`Timer` internals through a struct literal. Use the public state-transition
methods. Existing `Timer` and `Stopwatch` mutators already return a replacement
value, so retain the result, for example `timer = timer.tick(delta)`.

## Camera Primitives

`Aabb` no longer exports `inner : Aabb3d`; it stores six scalar center and
half-extent values. `Sphere` no longer exports `center : Vec3`; it stores three
scalar center values.

| Previous source | Replacement |
| --- | --- |
| `Aabb::{ inner }` | `Aabb::from_math(inner)` |
| `aabb.inner` | `aabb.to_math()` |
| `aabb.inner.center` | `aabb.center()` |
| `aabb.inner.half_size` | `aabb.half_size()` |
| `Sphere::{ center, radius }` | `Sphere::new(center, radius)` |
| `sphere.center` | `sphere.center()` |
| Scalar sphere construction | `Sphere::from_xyz(x, y, z, radius)` |

The scalar getters such as `center_x()` and `half_extents_x()` exist for hot
paths, but callers should not construct the flattened representation directly.

## Visibility

`InheritedVisibility` is now a value type with otherwise unchanged constructor
and getter APIs.

`ViewVisibility.bits` is no longer mutable. The former mutating
`ViewVisibility::update` method is deliberately not retained with a
value-returning signature: an old `view.update()` call would still compile,
discard the returned value, and silently preserve the old state. The
replacement is named `advance_frame` so unmigrated calls fail at compile time.

| Previous source | Replacement |
| --- | --- |
| `view.update()` | `view = view.advance_frame()` |
| `view.set_visible()` | `view = view.with_visible()` |
| `view.bits = bits` | Use `ViewVisibility::new`, `visible`, `hidden`, `with_visible`, or `advance_frame` |
| Component mutation through direct field access | Use `Write::set`, `Write::update`, or the `SetViewVisibility` API |

Code using ECS change detection must choose ordinary mutation or the explicit
bypass-change-detection API according to the same semantics as before; do not
replace every visibility write with a bypass update.

The former public `check_visibility_system` blanket producer was removed. It
marked every inherited-visible renderable as view-visible without applying the
camera-, layer-, range-, light-, or frustum-specific visibility owners. Normal
applications should install the root visibility plugin together with the
camera visibility plugin and relevant light plugins. A custom visibility
producer should set `ViewVisibility` through `SetViewVisibility` and run in
`visibility_set_check_visibility`; there is no source-faithful one-function
replacement for the old blanket scan.

## Texture Atlas

`TextureAtlas.layout` is now a private scalar asset id because the value type
cannot contain a reference-typed `Handle`.

| Previous source | Replacement |
| --- | --- |
| `TextureAtlas::{ layout, index }` | `TextureAtlas::new(layout, index)` |
| `atlas.layout` | `atlas.layout()` |
| Direct layout asset lookup through `atlas.layout` | `atlas.layout_asset(layout_assets)` |

`TextureAtlas.index` remains public. Prefer `index()` and `with_index()` when
the caller does not need field-pattern matching.

## ECS Change-Location Storage

`RawTableColumnKernel.changed_caller_ids` changed from `Array[Int]` to
`Array[Int]?`. Change-location allocation is now opt-in through
`World::new(track_change_locations=true)`.

Direct consumers of `RawTableColumnKernel` must handle `None`. `None` means the
world does not track caller locations; it is not an empty tracked column.
`RawTableColumnKernel` is a low-level storage type, so normal downstream ECS
code should use `Read::changed_by` and the corresponding query APIs instead of
accessing the raw field.

`EcsError` also gained `TableBatchUnavailable(String)`. Exhaustive downstream
matches must add that case or an explicit fallback arm.

`World::new` now accepts the optional `track_change_locations` argument.
Existing `World::new()` calls remain valid. Code that stored `World::new` as a
zero-argument function value should replace it with `() => World::new()`;
callers that need change locations should use
`World::new(track_change_locations=true)`.

## Bindless Material Allocation

`MaterialBindGroupBindlessAllocator::allocate` changed from
`MaterialBindingId?` to `MaterialBindingId`. A bindless allocator now grows a
new slab and cannot fail because the current slab is full.

Remove `Some`/`None` matching or `.unwrap()` from direct bindless allocator
calls:

```mbt nocheck
let binding = allocator.allocate(material_id)
```

The higher-level material allocator enum may still return `None` when a
bindless allocation is requested from a non-bindless allocator.

## Frustum System Generic Bound

`render3d_update_frusta_system_by_projection_key` now requires
`T : @ecs.Component`. Generic wrappers calling this function must add the same
bound. Concrete projection components that already implement `Component` need
no source change.

## Table-Batch Mutable Column Scope

`TableBatchWrite::update_inplace` and
`update_inplace_bypass_change_detection` now pass
`TableBatchMutValues[T]` instead of a raw `MutArrayView[T]`. The old view could
escape its callback and continue replacing ECS column values without a valid
lease, change ticks, or finalizer handling. A retained `TableBatchMutValues`
becomes inactive when the callback returns, and every subsequent indexed read
or write aborts.

Callbacks with inferred parameter types keep the same source shape:

```mbt nocheck
values.update_inplace(fn(items) {
for index in 0..<items.length() {
items[index] = update(items[index])
}
})
```

Explicit callback parameter annotations must change:

| Previous source | Replacement |
| --- | --- |
| `fn(items : MutArrayView[T]) { ... }` | `fn(items : TableBatchMutValues[T]) { ... }` |
| Retain `items` and write after the callback | Perform every indexed read and write inside the callback |

The controlled view deliberately exposes only `length()` and indexed
`op_get`/`op_set`; it does not expose its backing array or a raw mutable view.
Internally it keeps a private `MutArrayView` already bounded to the live rows,
so indexed access retains one bounds check without making the raw capability
escapable.

## Filtered Table Row Scope

`Query::try_for_each_filtered_table` exposes the complete physical table and a
separate `QueryTableRows` matcher. Row-indexed access through
`QueryTableBatch`, `TableBatchRead`, `TableBatchWrite`, or
`TableBatchChangeWriter` is valid only while `QueryTableRows::for_each` is
invoking the callback for that exact matching row. Use the yielded physical
row index directly:

```mbt nocheck
ignore(query.try_for_each_filtered_table(fn(batch, rows) {
let positions = batch.write(position_key).unwrap()
rows.for_each(fn(row_index) {
positions.set(row_index, update(positions.peek(row_index)))
})
}))
```

Code that indexed a different physical row from inside the callback could
previously read or mutate an entity rejected by `Changed`, `Added`, `Or`, or a
custom filter. That out-of-filter access now aborts. Whole-table batches from
`Query::for_each_table` retain unrestricted access to every live physical row.
The callback-scoped `with_read_values` and `with_write_values` helpers still
provide complete read-only column views; callers must use them only with row
indices yielded by the associated `QueryTableRows` traversal.

## Source-Compatible Interface Changes

The generated-interface audit also found additive changes that do not require
downstream migration: the table-batch query APIs, `ReadValue`, camera frustum
schedule symbols, and defaulted table-binding methods on the open query traits.
53 changes: 53 additions & 0 deletions docs/MOON_WESL_0_17_MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# moon_wesl 0.17.0 migration

## Version boundary

`Milky2018/moon_wesl` is upgraded from `0.1.2` to `0.17.0`. The 0.17 release
uses `Milky2018/wgsl` for WGSL parsing and semantic validation and exposes the
compiled syntax tree through `CompileResult`.

## Compile option API

The former `CompileOptions::with_*` builder methods were removed. Configure
the public record from `CompileOptions::default()` instead. Defaults still
enable imports, conditional compilation, stripping, lazy resolution, and
validation. Mgstudio only overrides `lower`, matching its previous behavior:

```mbt
let options = {
..@wesl.CompileOptions::default(),
lower: true,
features,
}
```

Feature flags now use `Features` and the four-state `Feature` enum rather than
boolean values stored directly in the options. Mgstudio preserves its existing
`ShaderDefVal::Bool` semantics with `Feature::from_bool(value)`. Integer and
unsigned shader definitions remain ignored by the WESL conditional compiler,
as before.

## Resolver and output behavior

The application-owned `ShaderResolver` still implements the published
`Resolver` trait, so asynchronous asset availability and
`ShaderImportNotYetAvailable` behavior are unchanged. `compile(...)` still
returns an object whose `to_string()` method emits WGSL for the render backend.

No mgstudio public API changes are introduced by this migration.

## Verification

- `moon check shader --target native --deny-warn`
- `moon test shader/shader_cache_test.mbt -f 'shader cache compiles wesl
through loaded shader assets and bool defs' --target native --release
--deny-warn`
- `moon test shader/wesl_runtime_test.mbt -f 'shader runtime wesl registration
compiles after imported module is loaded as shader asset' --target native
--release --deny-warn`
- `moon check --target native` (`0` errors; the existing 226 warnings are
tracked by ISS-443)
- frame-90 native capture of `examples/shader/shader_material_wesl`; the run
log is empty and the WESL material pipeline completes. Its existing visual
parity work remains part of ISS-157 and is not accepted by this dependency
migration.
14 changes: 11 additions & 3 deletions docs/PARITY_GATES.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ than external paths such as:

This preserves runtime asset provenance for example parity claims.

### `gate_bevy_asset_mirror.sh`

Checks the SHA-256 manifest for every tracked non-WGSL resource copied from the
pinned Bevy baseline. The gate runs without a local Bevy checkout; use
`scripts/sync_bevy_assets.py --check` when the pinned checkout is available to
verify both the mirrors and the checked-in manifest against their source files.

### `gate_visual_runtime.sh`

Runs a small visual screenshot gate over representative 3D examples. The gate
Expand Down Expand Up @@ -63,9 +70,10 @@ Related scripts:
the parity gate set:

1. `gate_no_mgstudio_shader.sh`
2. `gate_asset_provenance.sh`
3. `gate_visual_runtime.sh`
4. `gate_stress_performance.sh` (optional; enabled by env flag)
2. `gate_bevy_asset_mirror.sh`
3. `gate_asset_provenance.sh`
4. `gate_visual_runtime.sh`
5. `gate_stress_performance.sh` (optional; enabled by env flag)

For environments that should only run the static subset, set:

Expand Down
40 changes: 40 additions & 0 deletions docs/WGSL_DEPENDENCY_0_16_MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# WGSL Dependency 0.16 API Migration

This document records the source-breaking dependency boundary change retained
when the WGSL dependency family moved from `0.15.3` to `0.16.0`.

## Public API changes

The removed `Milky2018/wgsl/common` package must no longer appear in downstream
imports. Use the user-facing `Milky2018/moon_wgsl` facade for public contracts
and project policy:

| 0.15.3 import or call | 0.16.0 replacement |
| --- | --- |
| `Milky2018/wgsl/common` | `Milky2018/moon_wgsl` |
| `@common.default_wgsl_value_defines()` | `@moon_wgsl.bevy_wgsl_value_defines()` |
| direct public `directive` scanner imports | `@moon_wgsl.get_preprocessor_metadata()` and `@moon_wgsl.wgsl_source_define_import_path()` |

This changes the package owner printed for public `ShaderDefValue`,
`WgslComposeOptions`, `WgslSourceFile`, and `WgslSourceScanOptions` types in
generated interfaces. Their mgstudio API meaning is unchanged, but downstream
code with explicit `Milky2018/wgsl/common` imports or type annotations must
move those references to `Milky2018/moon_wgsl`.

Mgstudio still imports `Milky2018/moon_wgsl_naga_oil/compose` at its internal
runtime boundary because it requires the explicit
`compose_wgsl_runtime_valid` entry point. This low-level path is not re-exported
as an mgstudio public type.

## Runtime behavior

The runtime composer now registers the complete embedded shader registry and
lets the 0.16 composer resolve the active import graph. It no longer supplies a
locally precomputed root dependency subset for runtime composition. This is
required for conditional Bevy imports whose active dependencies depend on the
shader definitions passed to composition.

The 0.16 upgrade makes a minimal fully qualified module function call compose
and flatten successfully. The complete pinned-Bevy deferred-lighting graph
still fails on `bevy_pbr::fog::linear_fog`; that remaining external blocker is
tracked by ISS-405 and must not be hidden by rewriting copied WGSL.
Loading
Loading