Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 24 additions & 0 deletions .agents/rules/perf-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Performance Work Rules (ENG2)

Applies to any change under `**/rendering/**`, `**/graphics/**`, `**/benches/**`, `scripts/bench-gate.py`, or any issue labeled `area:performance`.

## Definition of done (non-negotiable)

A performance change is done only when BOTH hold:

1. **A named scripted scene hits its numeric target** — S1–S5/H1/cull_scaling from `docs/src/runbook/perf-dod.md`, captured via `scripts/perf-capture` (3-run median on Apple M-series/Metal) or the CI `scripts/bench-gate.py` ratio-gate for CI-runnable benches.
2. **A phase counter attributes the cost.** The relevant GPU/CPU phase timing is non-zero and accounts for the frame.

**A counter that reads zero means the instrumentation is broken, never that the work is free.** GPU cost surfaces at surface-acquire/present, not in a CPU command-record timer — measure it with a real GPU timestamp (QuerySet), do not infer it.

## Rules

- No optimization without a measurement first. Post the before-number, then the after-number, on the issue.
- Never silently cap coverage (top-N, sampling, windowing) to hit a number — `log`/document what was dropped. A scene-windowing workaround is a consumer band-aid, not an engine fix.
- The target is **O(visible), not O(total)**: per-frame CPU cost must not scale with total scene/entity count. If it does, that is the bug, regardless of FPS.
- Steady-state render frame (no scene mutation) must perform **0 heap allocations** in the render path — assert it with the alloc-budget harness (ENG2-P0-15), do not eyeball it.
- Aim for headroom, not the 60 FPS floor: the v2 targets are 120+ FPS for tens of thousands of visible entities.

## Before closing

Run the relevant bench-gate scene, attach the capture (scene, numbers, phase breakdown, delta vs baseline). See `docs/src/runbook/perf-dod.md` for scenes and targets and `[perf-work]`↔`[render-v2]`↔`[testing-v2]` for the companion rules.
25 changes: 25 additions & 0 deletions .agents/rules/render-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Render Core v2 Rules (ENG2 Phases 2 & 6)

Applies to `**/graphics/**` and the renderer paths. These invariants supersede the performance/submission guidance in `graphics-patterns.md` (the backend-isolation and Renderer-trait rules there still hold). Full design: `docs/src/runbook/phases/phase-2.md` and RFC-0005.

## Submission model

- **O(visible), never O(total).** No per-frame iteration over the entire scene-object set. Cull against a spatial index (grid/BVH) *before* any transform/uniform/encode work. A culled object must pay zero per-frame cost.
- **Dense storage, not hash-map iteration.** Scene objects live in slot arrays with generational handles, iterated contiguously — not a per-frame walk of a `FxHashMap`.
- **Instancing by identity.** Draws are grouped by `(mesh id, material id)` and submitted instanced by default — including `CreatePlane`/`CreateCube`/`CreateSphere`/`CreateCylinder` primitives, not only `InstantiateModel`. A config flag that claims to enable instancing must actually drive the instanced path or not exist.

## Uniforms & buffers

- **Per-frame constants uploaded once** (camera, lights, fog) into one bind group. **Per-object data goes in dynamic-offset slots** — never copy a full multi-KB uniform block per draw, never issue one `write_buffer` per draw. Coalesce writes into one upload per frame.
- **Persistent, dirty-tracked instance/transform buffers.** Upload only changed ranges. Never rebuild the whole buffer, and never CPU-pre-transform vertices into a static VBO that must be re-baked on any change.
- Do not clone per-instance CPU vertex data for instances that share a mesh.

## Data seam

- Transforms are a **structure-of-arrays column shared between ECS and the renderer** (ENG2-P2-13). The renderer consumes dirty ranges from that column; it does not receive per-entity transforms across FFI one at a time.

## Every render/UI/particle change

- Add or update a **story** in the scene gallery (ENG2-P0-14) with a golden image and metric budget — see `[testing-v2]`.
- Meet the perf definition of done — see `[perf-work]` and `docs/src/runbook/perf-dod.md`.
- Raw GPU calls stay in `libs/graphics/backend/` (unchanged boundary).
30 changes: 30 additions & 0 deletions .agents/rules/testing-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Testing v2 Rules (ENG2)

Applies to all ENG2 work. Full strategy: `docs/src/runbook/testing-strategy.md`. Extends `testing.md` (GL-context and unit conventions there still hold).

## Spec-first (TDD)

- Every behavioral issue gets a spec test at `goud_engine/tests/spec/eng2_p<N>_<nn>_<slug>.rs` encoding its Acceptance Criteria as executable assertions. The spec **is** the gate evidence.
- Write the spec RED before the implementation; make it GREEN; then REFACTOR. A reviewer confirms it was red-before-green.
- The issue's Verification section names the spec path. Do not close an issue whose spec test does not exist or does not assert its acceptance criteria.

## Tiers — put each test at the right level

- **Unit** — pure logic, no GPU. Design v2 render/ECS logic (culling, instancing-grouping, sort-key, propagation) to be unit-testable without a GPU context.
- **Isolation** — one subsystem behind its null/provider boundary (`NullBackend`, null net/audio, in-memory VFS). If the seam to mock a dependency is missing, add the null/mock provider.
- **Integration** — cross-layer in-process; assert exact draw/culled/visible counts (generalize `tests/renderer3d_frame_counts.rs`).
- **E2E** — SDK-driven headless engine (ENG2-P0-17); C#/TS/Python boot a real engine, run a scripted game, assert counts/world-hash/flat-RSS.

## Story gallery

- Every render/UI/particle/animation change adds or updates a **story** (ENG2-P0-14): scene + camera + knobs + expected invariants + golden image. CI renders it headless, diffs the golden, checks metric budgets, and publishes the HTML gallery.
- Changing a golden requires the documented golden-update approval — do not silently overwrite baselines.

## Determinism, property, fuzz

- Sim/scheduling changes run the determinism fixture (3 seeds × 10k ticks, hash-compare). Do not introduce nondeterminism (unordered iteration, wall-clock reads, FP drift).
- Component-store and command-decoder changes add/extend `proptest` + `cargo-fuzz` targets (ENG2-P0-18, P3-09).

## Don't game the gate

Never weaken an assertion, widen a tolerance, or skip a scene to make a gate pass. If a gate is wrong, fix the gate in the same PR with justification.
31 changes: 31 additions & 0 deletions .cursor/rules/perf-work.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
description: Performance Work Rules (ENG2)
globs:
alwaysApply: true
---

<!-- AUTO-GENERATED by scripts/sync-agent-configs.py. Edit .agents/rules/perf-work.md, then rerun the generator. -->
# Performance Work Rules (ENG2)

Applies to any change under `**/rendering/**`, `**/graphics/**`, `**/benches/**`, `scripts/bench-gate.py`, or any issue labeled `area:performance`.

## Definition of done (non-negotiable)

A performance change is done only when BOTH hold:

1. **A named scripted scene hits its numeric target** — S1–S5/H1/cull_scaling from `docs/src/runbook/perf-dod.md`, captured via `scripts/perf-capture` (3-run median on Apple M-series/Metal) or the CI `scripts/bench-gate.py` ratio-gate for CI-runnable benches.
2. **A phase counter attributes the cost.** The relevant GPU/CPU phase timing is non-zero and accounts for the frame.

**A counter that reads zero means the instrumentation is broken, never that the work is free.** GPU cost surfaces at surface-acquire/present, not in a CPU command-record timer — measure it with a real GPU timestamp (QuerySet), do not infer it.

## Rules

- No optimization without a measurement first. Post the before-number, then the after-number, on the issue.
- Never silently cap coverage (top-N, sampling, windowing) to hit a number — `log`/document what was dropped. A scene-windowing workaround is a consumer band-aid, not an engine fix.
- The target is **O(visible), not O(total)**: per-frame CPU cost must not scale with total scene/entity count. If it does, that is the bug, regardless of FPS.
- Steady-state render frame (no scene mutation) must perform **0 heap allocations** in the render path — assert it with the alloc-budget harness (ENG2-P0-15), do not eyeball it.
- Aim for headroom, not the 60 FPS floor: the v2 targets are 120+ FPS for tens of thousands of visible entities.

## Before closing

Run the relevant bench-gate scene, attach the capture (scene, numbers, phase breakdown, delta vs baseline). See `docs/src/runbook/perf-dod.md` for scenes and targets and `[perf-work]`↔`[render-v2]`↔`[testing-v2]` for the companion rules.
32 changes: 32 additions & 0 deletions .cursor/rules/render-v2.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
description: Render Core v2 Rules (ENG2 Phases 2 & 6)
globs:
alwaysApply: true
---

<!-- AUTO-GENERATED by scripts/sync-agent-configs.py. Edit .agents/rules/render-v2.md, then rerun the generator. -->
# Render Core v2 Rules (ENG2 Phases 2 & 6)

Applies to `**/graphics/**` and the renderer paths. These invariants supersede the performance/submission guidance in `graphics-patterns.md` (the backend-isolation and Renderer-trait rules there still hold). Full design: `docs/src/runbook/phases/phase-2.md` and RFC-0005.

## Submission model

- **O(visible), never O(total).** No per-frame iteration over the entire scene-object set. Cull against a spatial index (grid/BVH) *before* any transform/uniform/encode work. A culled object must pay zero per-frame cost.
- **Dense storage, not hash-map iteration.** Scene objects live in slot arrays with generational handles, iterated contiguously — not a per-frame walk of a `FxHashMap`.
- **Instancing by identity.** Draws are grouped by `(mesh id, material id)` and submitted instanced by default — including `CreatePlane`/`CreateCube`/`CreateSphere`/`CreateCylinder` primitives, not only `InstantiateModel`. A config flag that claims to enable instancing must actually drive the instanced path or not exist.

## Uniforms & buffers

- **Per-frame constants uploaded once** (camera, lights, fog) into one bind group. **Per-object data goes in dynamic-offset slots** — never copy a full multi-KB uniform block per draw, never issue one `write_buffer` per draw. Coalesce writes into one upload per frame.
- **Persistent, dirty-tracked instance/transform buffers.** Upload only changed ranges. Never rebuild the whole buffer, and never CPU-pre-transform vertices into a static VBO that must be re-baked on any change.
- Do not clone per-instance CPU vertex data for instances that share a mesh.

## Data seam

- Transforms are a **structure-of-arrays column shared between ECS and the renderer** (ENG2-P2-13). The renderer consumes dirty ranges from that column; it does not receive per-entity transforms across FFI one at a time.

## Every render/UI/particle change

- Add or update a **story** in the scene gallery (ENG2-P0-14) with a golden image and metric budget — see `[testing-v2]`.
- Meet the perf definition of done — see `[perf-work]` and `docs/src/runbook/perf-dod.md`.
- Raw GPU calls stay in `libs/graphics/backend/` (unchanged boundary).
37 changes: 37 additions & 0 deletions .cursor/rules/testing-v2.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
description: Testing v2 Rules (ENG2)
globs:
alwaysApply: true
---

<!-- AUTO-GENERATED by scripts/sync-agent-configs.py. Edit .agents/rules/testing-v2.md, then rerun the generator. -->
# Testing v2 Rules (ENG2)

Applies to all ENG2 work. Full strategy: `docs/src/runbook/testing-strategy.md`. Extends `testing.md` (GL-context and unit conventions there still hold).

## Spec-first (TDD)

- Every behavioral issue gets a spec test at `goud_engine/tests/spec/eng2_p<N>_<nn>_<slug>.rs` encoding its Acceptance Criteria as executable assertions. The spec **is** the gate evidence.
- Write the spec RED before the implementation; make it GREEN; then REFACTOR. A reviewer confirms it was red-before-green.
- The issue's Verification section names the spec path. Do not close an issue whose spec test does not exist or does not assert its acceptance criteria.

## Tiers — put each test at the right level

- **Unit** — pure logic, no GPU. Design v2 render/ECS logic (culling, instancing-grouping, sort-key, propagation) to be unit-testable without a GPU context.
- **Isolation** — one subsystem behind its null/provider boundary (`NullBackend`, null net/audio, in-memory VFS). If the seam to mock a dependency is missing, add the null/mock provider.
- **Integration** — cross-layer in-process; assert exact draw/culled/visible counts (generalize `tests/renderer3d_frame_counts.rs`).
- **E2E** — SDK-driven headless engine (ENG2-P0-17); C#/TS/Python boot a real engine, run a scripted game, assert counts/world-hash/flat-RSS.

## Story gallery

- Every render/UI/particle/animation change adds or updates a **story** (ENG2-P0-14): scene + camera + knobs + expected invariants + golden image. CI renders it headless, diffs the golden, checks metric budgets, and publishes the HTML gallery.
- Changing a golden requires the documented golden-update approval — do not silently overwrite baselines.

## Determinism, property, fuzz

- Sim/scheduling changes run the determinism fixture (3 seeds × 10k ticks, hash-compare). Do not introduce nondeterminism (unordered iteration, wall-clock reads, FP drift).
- Component-store and command-decoder changes add/extend `proptest` + `cargo-fuzz` targets (ENG2-P0-18, P3-09).

## Don't game the gate

Never weaken an assertion, widen a tolerance, or skip a scene to make a gate pass. If a gate is wrong, fix the gate in the same PR with justification.
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Source of truth: `.agents/agent-catalog.toml` and `.agents/role-specs/*.md`.

## Rules

Read only rules matching your change area: `.agents/rules/*.md`.
Read only rules matching your change area: `.agents/rules/*.md`. Active roadmap: v2 rebuild ("ENG2") — `docs/src/runbook/` + pinned master issue #810 (perf/render/test rules: `perf-work.md`, `render-v2.md`, `testing-v2.md`).

## Local AGENTS Files

Expand Down
17 changes: 13 additions & 4 deletions ALPHA_ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
# GoudEngine Alpha Roadmap

## Completion Status
# GoudEngine Alpha Roadmap (ARCHIVED)

> **ARCHIVED — DO NOT USE FOR PLANNING.** This is the historical alpha (v1) roadmap.
> Its status claims are unreliable: the "Phase 0 (v2): Core Performance — COMPLETE"
> line below was false when written — #677, #678, and #679 were open priority:high
> perf bugs at the time, and the v2 perf gate (60 fps @ 10k entities) was never
> validated against a consumer-scale scene.
>
> **The current roadmap is the v2 Rebuild Runbook: `docs/src/runbook/phase-index.md`
> and the pinned master tracking issue (ENG2 #810).** Historical body preserved below.

## Completion Status (v1 — historical)
- [x] Phase 0 (v1): Foundation -- COMPLETE
- [x] Phase 1 (v1): Core Stabilization -- COMPLETE
- [x] Phase 2 (v1): Core Systems -- COMPLETE
- [x] Phase 2.5 (v1): AI Debugger & Runtime Observability -- COMPLETE
- [x] Phase 3 (v1): Rendering Pipeline + SDK Expansion -- COMPLETE
- [x] Phase 0 (v2): Core Performance (GoudEngine side) -- COMPLETE
- [ ] Phase 0 (v2): Core Performance -- SUPERSEDED by ENG2 (was falsely marked COMPLETE)

## Vision

Expand Down
21 changes: 21 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,27 @@
- [Governance and Enforcement](development/governance.md)
- [Performance Roadmap](development/performance-roadmap.md)

# v2 Rebuild Runbook (ENG2)

- [Runbook Overview](runbook/index.md)
- [Phase Index](runbook/phase-index.md)
- [Perf Definition of Done](runbook/perf-dod.md)
- [Testing Strategy](runbook/testing-strategy.md)
- [Throne Sync](runbook/throne-sync.md)
- [Roadmap Issue Template](runbook/issue-template.md)
- [Phase Specs (full)](runbook/phase-specs.md)
- [Phase Specs — Perf/Test Expansion](runbook/phase-specs-expansion.md)
- [Phase 0: Instrumentation, Truth & Test Foundation](runbook/phases/phase-0.md)
- [Phase 1: SDK Single Source of Truth](runbook/phases/phase-1.md)
- [Phase 2: Render Core v2](runbook/phases/phase-2.md)
- [Phase 3: Data Core v2](runbook/phases/phase-3.md)
- [Phase 4: FFI v2 Convergence](runbook/phases/phase-4.md)
- [Phase 5: Parallelism & Determinism](runbook/phases/phase-5.md)
- [Phase 6: 2D Render v2](runbook/phases/phase-6.md)
- [Phase 7: Runtime Services](runbook/phases/phase-7.md)
- [Phase 8: Capability Gaps](runbook/phases/phase-8.md)
- [Phase 9: Authoring & Release](runbook/phases/phase-9.md)

# Architecture

- [SDK-First Architecture](architecture/sdk-first.md)
Expand Down
Loading
Loading