155 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5297c94180 |
docs(nigig-build): add audited remediation execution plan
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
|
||
| ac8f8aa002 |
chore: sync full working tree to gitdab
Some checks failed
Payment domain, storage, platform and UI / isolated-payment-tests (push) Waiting to run
Payment domain, storage, platform and UI / payment-ui-tests (push) Waiting to run
repo hygiene / hygiene (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
traffic / gates (push) Has been cancelled
traffic / nigig-traffic (push) Has been cancelled
traffic / supply-chain (push) Has been cancelled
doc-engine / engine (push) Has been cancelled
doc-engine / coverage (push) Has been cancelled
doc-engine / consumer (push) Has been cancelled
email / gates (push) Has been cancelled
email / email-domain (push) Has been cancelled
email / nigig-email (push) Has been cancelled
email / supply-chain (push) Has been cancelled
nigig-map / test (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
spreadsheet / engine-coverage (push) Has been cancelled
spreadsheet / ui-controller-coverage (push) Has been cancelled
Whole-tree sync: cad-core/cad-ui split sources, nigig-build construction_frame migration, pdf port progress, mpesa/pay/uikit/doc updates, workspace members/profiles/lock, CI workflows and reviews. See individual file history for details. |
|||
| 338b8c818f |
fix(android): enable cad-ui on mobile + new-API fixes
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
spreadsheet / engine-coverage (push) Has been cancelled
spreadsheet / ui-controller-coverage (push) Has been cancelled
- nigig-build: cad-ui + construction_frame back on unconditionally. The host-only gate is dropped: cad-ui now compiles for aarch64, and pageflipnav mobile needs ConstructionScreen / BuildProjectsPage (CAD/Docs/Spreadsheet buttons) — gating produced the white screen. - cad-ui: ScriptVmHost for standalone eval (no more vm.std / () host), std::thread workers (Cx::spawn_thread removed upstream). - viewport: same worker fix + section_state helper for the CPU cull path. - script_bindings: new script/geometry binding module. - spreadsheet grid + invoice Walk literals: ..Default::default() for new aspect/cell/deferred fields; explicit style::CellAlign import (makepad added its own CellAlign). Verified: pageflipnav aarch64 release links with 0 errors; APK built, installed (54M) and running with home screen drawing. |
|||
| 5ae5d5a84c |
fix(android): gate cad-ui host-only + port map to new makepad API
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
nigig-map / test (push) Has been cancelled
- nigig-build: cad-ui + construction_frame host-only (DO NOT enable unconditionally: CadViewport Script derive fails ScriptApply for aarch64 and breaks every pageflipnav android build). - map: vendor TagThreadPool (removed upstream with the task-pool scheduler) into thread_pool.rs; Walk literals gain ..Default::default() for new aspect/cell/deferred fields. Verified by pageflipnav aarch64 release rust build (0 errors). |
|||
| c901f1d4f1 |
chore(deps): bump makepad fork rev to b9a083c26 + workspace updates
Some checks failed
doc-engine / engine (push) Has been cancelled
doc-engine / coverage (push) Has been cancelled
doc-engine / consumer (push) Has been cancelled
email / gates (push) Has been cancelled
email / email-domain (push) Has been cancelled
email / nigig-email (push) Has been cancelled
email / supply-chain (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
nigig-map / test (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
spreadsheet / engine-coverage (push) Has been cancelled
spreadsheet / ui-controller-coverage (push) Has been cancelled
Fork nigig-makepad-test-android now at b9a083c26 (upstream merge + robot secondary-dex bundling + app_main wrapper fix, on top of the game-libs/arcade port). All 16 workspace makepad revs follow. Also takes the in-tree workspace updates: exclude nested crates/nimanyatta workspace, add crates/apps/nigig-site member, and PERF-OPS Phase 1 profile tuning (thin LTO + engine opt-level 3). cad-core/cad-ui split and nigig-traffic members stay WIP. |
|||
| 12dff81b05 |
fix(build): make cad-ui host-only for Android
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
cad-ui's Widget Script derive (CadViewport) needs LiveHook fix for aarch64; until then, gate it behind cfg(not(target_os="android")) in nigig-build so pageflipnav's aarch64 wrapper (which pulls nigig-build) can link without cad-ui. Host builds still include cad-ui. Unblocks pageflipnav aarch64 release. |
|||
| 212abe6e8b |
refactor(cad): port AI subsystem from makepad-ai Agent API to makepad-ai-hub worker-thread ChatProvider model (adopt upstream example/cad), bump makepad fork rev to 7bddebb
Some checks failed
doc-engine / engine (push) Has been cancelled
doc-engine / coverage (push) Has been cancelled
doc-engine / consumer (push) Has been cancelled
email / gates (push) Has been cancelled
email / email-domain (push) Has been cancelled
email / nigig-email (push) Has been cancelled
email / supply-chain (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
nigig-map / test (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
spreadsheet / engine-coverage (push) Has been cancelled
spreadsheet / ui-controller-coverage (push) Has been cancelled
|
|||
| 560116189c |
fix(cad-build): land CAD workspace on project dashboard, not a blank editor
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
The CAD dashboard's CadDashboard node never realized as a widget, so tapping 'CAD Workspace' opened to a blank/editor-only sheet. Empirical device dumps showed the first child after the root realizes reliably while a sibling placed after the editor AdaptiveView does not, and a root ':=' widget child alone never realizes here. - Place dashboard_layer as the FIRST direct child of CadWorkspaceBase, wrapping mod.widgets.CadDashboard so it is a reliably-realizable, togglable View layer (matching the working doc workspace pattern). - Wrap the editor AdaptiveView in editor_layer (a plain View) and toggle editor_layer/dashboard_layer visibility from apply_dashboard_visibility instead of toggling the AdaptiveView variants, which always draw their active variant regardless of visible. - Add use mod.widgets.* to the CadDashboard script_mod (matches the CadEditorSheet registration that realizes inside this workspace). - Add regression test candlands_on_dashboard asserting the dashboard title and + New Project button land when opening the workspace. |
|||
| 1d8b3a6053 |
merge(local): reapply local WIP onto merged main -- cad dashboard/explode/script_parts/xray merged with remote Phase-5 LOD, plus doc-ui extraction, spreadsheet xls-import, android ussd, camera and test work
Some checks failed
makepad-table / model (push) Has been cancelled
makepad-table / widget (push) Has been cancelled
makepad-table / hygiene (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
Payment domain, storage, platform and UI / isolated-payment-tests (push) Has been cancelled
Payment domain, storage, platform and UI / payment-ui-tests (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
doc-engine / engine (push) Has been cancelled
doc-engine / coverage (push) Has been cancelled
doc-engine / consumer (push) Has been cancelled
email / gates (push) Has been cancelled
email / email-domain (push) Has been cancelled
email / nigig-email (push) Has been cancelled
email / supply-chain (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
nigig-map / test (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
spreadsheet / engine-coverage (push) Has been cancelled
spreadsheet / ui-controller-coverage (push) Has been cancelled
|
|||
| 159f3c7fee | Merge remote-tracking branch 'origin/main' | |||
| c7c0ec7582 |
makepad: centralize fork deps in workspace + bump to 4a166606c
Declare the 12 makepad crate deps once in root [workspace.dependencies] pointing at the gitdab fork rev 4a166606c (which now also carries [workspace.dependencies] into the android wrapper manifest). Member crates switch to workspace = true; 5 non-member workspaces get an inline rev bump. Fix 9 nigig-app script_mod indent errors surfaced by the newer upstream macro parser. The fork rev includes: NIGIG test-mode forwarding, custom AndroidManifest hook, ortho camera support, and the wrapper workspace-deps fix. |
|||
| cbce585eb4 |
perf(cad): complete 2D and 3D LOD -- Phase 5
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
The first Phase 5 tranche correctly reduced sub-pixel 2D outlines, but it stopped short of the plan's full level-of-detail phase. Complete the phase by applying the same measured three-pixel policy to the 3D path. Visible 3D parts below the projected AABB threshold now use one shared unit-cube geometry with an axis-aligned world-bounds transform. Full-detail shape batches, proxy instance rows and proxy draw calls are reported separately. Wireframe and hidden-line overlays use the same policy, and selected or hovered parts remain full detail. Extend the host-testable projection and proxy policy tests, frame benchmark, source guards and documentation. Keep the real GPU/window visual check explicit: compilation, policy arithmetic, submission structure and coverage pass here, but this environment cannot execute Makepad's draw submission. |
|||
| a5ba719d8d |
perf(cad): add measured sub-pixel LOD to the 2D path -- Phase 5
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
Phase 4 reduced the number of tessellation calls, but it left the geometry volume unchanged: a zoomed-out 2,000-part plan still queued a full outline for every visible part. At the measured 200 m site view a 1 m part is only about 2.7 logical pixels across, so the remaining geometry was not resolvable detail. Add a pure lod policy that projects plane extents into logical pixels, keeps selected and hovered parts full detail, and conservatively falls back to a full outline for malformed state. The renderer and CadViewport::frame_budget call the same policy. Ordinary sub-pixel parts use one bounded 2x2 filled marker, while FrameBudget reports full outlines, markers, strokes and fills separately. Also fold the remaining 2D 1.2 margins into render_budget::VIEW_MARGIN, extend the structural benchmark and coverage harness, correct the phase documentation, and explicitly leave 3D mesh LOD deferred until a real GPU/window measurement justifies a second geometry policy. |
|||
| 7a55f99c3a | Merge remote-tracking branch 'origin/main' | |||
| 4cbb155cb7 |
perf(cad): stroke per group, not per item -- Phase 4 of the render plan
Some checks failed
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
A 2,000-part plan view with everything on screen cost 2,270 tessellation
calls a frame. It now costs four: two for the grid, two for the parts.
`stroke()` tessellates the whole accumulated path and clears it --
`tessellate_path_stroke` ends in `path.clear()` -- so queueing many
subpaths and stroking once is one tessellation instead of N. The idiom
was already in this file: `queue_dashed_line` has done it for the axis
grid since Phase 3.9, guarded by a test. Phase 4 applies it to the two
loops that never adopted it.
**Base grid: two passes, two strokes.** Minors queued and stroked at
0.55, majors at 1.6 -- the stroke width is the one thing that genuinely
needs its own call. `GridRange::has_minor_lines`/`has_major_lines`
decide whether a pass runs at all and `frame_budget` counts strokes with
the same two predicates, because an empty `stroke()` still enters the
tessellator and a budget that assumed two when the renderer made one
would be wrong in the direction that hides work. Minors stroke first so
majors land on top where they cross; same colour either way, so the only
visible difference is that the thicker line wins a crossing, which is
the right answer.
**Parts grouped by colour.** New `batching::ColorKey` -- the bit pattern,
because `f32` is not `Hash` and two colours whose bits differ are two
colours -- feeding the same `group_in_first_appearance_order` that
Phase 3 groups shapes with. The colour policy moved out of the two draw
loops into `constants::part_outline_color`, so the renderer and
`frame_budget` cannot disagree about how many groups a frame has; the 2D
loop had `vec4(1.0, 0.82, 0.40, 1.0)` written out where
`PART_SELECT_COLOR` already existed.
**Selected and hovered parts stroke last**, in their own groups, so a
highlight is never hidden under a neighbour's outline. They were
interleaved in document order before and could be.
`FrameBudget` gained `grid_lines` and `part_outlines` beside the call
counts. Geometry volume and call count are different numbers now and
both are worth reading -- `VectorSubmission { outlines, stroke_calls }`
mirrors Phase 3's `MeshSubmission` for the same reason.
Measured (bench_frame_submission_budget, 1920x1080, 200 m site):
zoom 5 m, 2000 parts: 12 visible outlines -> 4 tessellations (was 2170)
zoom 200 m, 2000 parts: 2000 visible outlines -> 4 tessellations (was 2270)
The second row is the point, and it is the row Phase 1 could not move:
everything is on screen, culling removes nothing, and the frame still
costs four calls.
WHAT THIS DOES NOT DO: vertex volume is unchanged. The same 2,000
rectangles are tessellated -- in two calls rather than 2,000. What is
saved is per-call overhead: tessellator setup, two `std::mem::take`s and
an `append_geometry` each time. If a 2,000-part plan view is still slow
after this, the remaining cost is triangles, which is Phase 5 and should
only happen if a measurement asks for it.
One visible-behaviour caveat, stated rather than buried: parts of the
same colour are now drawn together, so where two outlines of *different*
colours overlap, which is on top can change. They are 1.8 px outlines
and the highlight ordering got strictly better, but it is a change to
what is drawn, not only to how.
Two tests were wrong before the code was, which is becoming this plan's
pattern. `constants.rs` fell to 81.82% and the coverage floor caught it
-- `part_outline_color` had no tests, and it now has five. And the guard
test's first draft looked for a closing brace at a fixed indentation,
matched the wrong one, and failed on correct code; it matches braces
properly now.
Verified: tools/test-cad-coverage.sh green -- total 97.33%, batching.rs
100%, cull.rs 100%, render_budget.rs 99.68%, constants.rs 98.55%, all
floors met; cargo check --locked -p nigig-build --lib clean; cargo test
--lib 1114 passed (1100 + 14 new); --test cad_integration 154 passed;
CAD_BENCH=1 harness green; cargo fmt --check and git diff --check clean.
|
|||
| dc1defd7e8 |
perf(cad): one draw call per shape, not per part -- Phase 3 of the render plan
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
A 2,000-part model of six repeated shapes now draws in six calls. It
drew in 2,000 before, and in 733 after Phase 1 culling at a working
camera distance -- but at 400 m, with the whole site on screen and
nothing to cull, it still drew in 2,000. Culling decides which parts are
submitted; instancing decides how many calls carry them. They are
different axes and this is the one that does not care where the camera
is.
No shader change was needed and that was the surprise of the phase.
`DrawCadMesh`'s `transform`, `color`, `depth_clip` and `display_mode`
are `#[live]` fields after `#[deref] draw_vars` in a `#[repr(C)]` struct,
which is precisely the per-instance row `DrawVars::as_slice` packs and
sends. The loop was already sending instance rows -- one per call. Three
methods (`begin_instances`, `push_instance`, `end_instances`), ported
from `DrawPbr::begin_many_instances_for_mesh` in the pinned fork, keep
the call open across a group instead.
New `batching.rs` (pure, 100% covered, floored):
group_in_first_appearance_order(items) -> Vec<(K, Vec<T>)>
batch_count(keys) -> usize
First-appearance order rather than iterating a `HashMap`, deliberately.
`HashMap` order is randomised per process, so batch order -- and the
order parts reach the GPU -- would differ between runs and after a
rehash. For opaque depth-tested geometry that is invisible, which is
exactly what makes it a bad thing to depend on: the day someone adds a
translucent material it becomes a flicker that reproduces on one machine
in five.
`FrameBudget` now carries `MeshSubmission { instances, batches }`. Named
fields rather than a second positional `usize` because the entire point
of the phase is that the two numbers now differ, and a caller that
swapped them would report the win backwards.
Measured (`bench_frame_submission_budget`, counts):
camera 20 m, 2000 parts: 733 visible -> 6 draw calls (was 2000)
camera 80 m, 2000 parts: 1459 visible -> 6 draw calls (was 2000)
camera 400 m, 2000 parts: 2000 visible -> 6 draw calls (was 2000)
...and with every part a different size, 733/1459/2000 -- the ceiling,
which is in the table for the same reason Phase 2's is.
WHAT IS NOT VERIFIED, plainly. The instanced submission has never run.
There is no GPU, no window and no `Cx` here, and tests/ui.rs still fails
at child-build exit 101. What is verified: it compiles against the real
Makepad API; the grouping is right (seven tests, including "no item is
lost or duplicated", which is the failure mode hardest to see in a
screenshot); the budget arithmetic is right; and the batch cannot be
left open on any path -- `every_instanced_batch_is_closed_before_the_loop_turns`
is a source check in the same style as the redraw_all guard, because a
batch left open drops its rows and the parts simply vanish with no error
anywhere.
Someone with a window needs to open a 3D model and confirm the picture
is unchanged. Two things limit the damage if it is not: `begin_instances`
returning false falls back to the old one-call-per-part loop (it returns
false while the draw shader is still compiling, which happens on the
first frames of every window), and batch order is deterministic, so a
defect reproduces instead of flickering.
Verified: tools/test-cad-coverage.sh green -- batching.rs 100%, cull.rs
100%, total 97.30%, all floors met; cargo check --locked -p nigig-build
--lib clean at the 127-warning baseline; cargo test --lib 1100 passed
(1091 + 9 new); --test cad_integration 154 passed; CAD_BENCH=1 harness
green; cargo fmt --check and git diff --check clean.
|
|||
| 1e5d014198 |
perf(cad): one GPU buffer per shape, not per part -- Phase 2 of the render plan
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
Two hundred identical columns held two hundred GPU vertex buffers. They build byte-identical triangles -- `CadSolid::build_mesh` is a pure function of the solid payload and returns local-space geometry, and the upload path (`part_mesh_buffers_from_mesh` -> `MeshSpace::Model`) carries no transform and no colour -- so the duplication bought nothing but memory and upload time. `part_geoms` is now `HashMap<ShapeHash, Geometry>`. **ShapeHash**, new in cad_scene.rs: the solid payload and nothing else. No node id, no transform, no material. `ParamHash` is now *defined in terms of it* -- `id` then `ShapeHash` -- rather than repeating the match arm by arm. That is deliberate: last commit corrected a plan written on the assumption that equal `ParamHash` meant "same shape", which the leading `node.id.hash()` quietly made false. With one shared body the two hashes cannot drift apart again, and `param_hash_moves_whenever_the_shape_hash_moves` pins the join. Three consequences worth naming: - **Staleness became structural.** The key IS the content hash, so the draw loop's `.filter(|(hash, _)| *hash == ParamHash::from_node(part))` is gone: an edited part looks up a key that does not exist yet and `ensure_part_geometry` uploads it on the same frame. There is no "entry uploaded from different parameters" state left to guard against, which is the class of bug `subdivide_selected` shipped. - **Eviction is by live shape, not live id.** This is the hazard the change introduces and it is not obvious: deleting one of two hundred identical columns must NOT drop the buffer the other 199 draw from. An eviction written as "remove the deleted node's entry" would blank most of the model. `geometry_is_retained_by_live_shape_not_by_live_id` pins it. - **Uploads deduplicate within the frame.** Without the `queued` set, the first frame of a 200-column scene would call `get_or_build` two hundred times before the map had anything in it. Measured (`bench_geometry_buffers_shared_by_shape`, counts not timings): 200 identical walls 200 parts -> 1 buffer (200x) 420-part repetitive model 420 parts -> 6 buffers (70x) 420 all-distinct parts 420 parts -> 420 buffers (1x) The last row is in the table on purpose. Sharing is a property of the model, not of the code; a scene where every part differs gets nothing from this phase. And draw calls are unchanged -- still one per visible part -- exactly as the plan predicted. Collapsing those is Phase 3, which needed these shared buffers to be possible at all. Estimated at a week, took under a day. Two things the estimate did not know: `MeshCache::get_or_build` was already a pure function of `node.solid`, and the upload path already produced transform-free, colour-free buffers. It assumed both would need untangling; they were built right the first time. Verified: tools/test-cad-coverage.sh green -- total 97.27%, cad_scene.rs 98.56%, cull.rs 100%, all floors met; cargo check --locked -p nigig-build --lib clean (and one warning fewer: the `ParamHash` re-export in mod.rs is no longer needed by the widget layer); cargo test --lib 1091 passed (1085 + 6 new); --test cad_integration 154 passed; CAD_BENCH=1 harness green; cargo fmt --check and git diff --check clean. |
|||
| 4aaebafe4e |
perf(cad): cull parts against the viewport -- Phase 1 of the render plan
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
Before this, `grep -niE "cull|frustum|offscreen|in_view"` over the 2,438
line renderer returned nothing. Every part in the document was
tessellated in 2D and issued its own draw call in 3D, on screen or not.
At a 5 m drafting zoom over a 200 m site, a 2,000-part model spent 2,000
tessellations and 2,001 draw calls per frame to show twelve parts.
New `cull.rs` -- pure, host-testable, 100% covered with a floor in
tools/test-cad-coverage.sh:
draw_part_2d(centre, half_w, half_h, view, decorated) -> bool
Frustum::from_view_projection(view, projection) -> Frustum
Frustum::draw_part_3d(aabb, decorated) -> bool
world_aabb_from_local_bounds(min, max, model) -> WorldAabb
It lives in its own module for the same reason nav_pad.rs and
render_budget.rs do: viewport_render.rs is 2,438 lines at 0.00% coverage
and needs a Cx, so a predicate written inline there could not be tested
at all. Both draw loops AND CadViewport::frame_budget call these same
functions, which is what stops the reported budget from drifting away
from what is drawn -- the discipline render_budget.rs already applies to
the grid loops.
Measured (bench_frame_submission_budget, 1920x1080, parts on a 200 m
site; full tables in BENCH_BASELINE.md):
2D, 5 m zoom, 2,000 parts: 12 visible. 2,170 -> 182 tessellations,
2,001 -> 13 draw calls.
3D, 20 m camera, 2,000: 733 draw calls, 63% culled.
3D, 80 m camera, 2,000: 1,459 draw calls, 27% culled.
Whole site on screen: nothing culled, and nothing should be.
That last row is the honest half and it is in the doc too: when the view
holds the whole model, all 2,000 parts are genuinely visible and culling
cannot help. Phases 2 and 3 (shape-shared geometry, then instancing) are
what address that case.
Three things came out different from the plan I wrote last commit, and
the plan was wrong about each:
- **AABB, not bounding sphere.** A sphere around an AABB is looser at
the same cost -- a 6 m wall gets a 3 m radius ball. The p-vertex
AABB-versus-plane test is strictly tighter. So there is no
bounding_sphere helper, and in particular no bounding_sphere FIELD on
CadNode: the AABB is already cached by PlacedHash in SceneCache, which
invalidates itself on a move or a resize, where a stored field would
have to be maintained at 77 construction sites.
- **world_aabb_from_local_bounds is shared with pick_part**, replacing
the eight-corner transform that was inline there. Two copies would be
two chances to disagree about a part's bounds, and picking a part the
renderer culled is precisely the bug that disagreement produces.
- **The "drawn extent" hazard split into two concrete rules.** The 2D
test takes part_to_plane_2d and part_size_on_plane -- the very values
the draw uses -- so it tests the drawn rect, not the model extent. And
no selected or hovered part is ever culled: the highlight and the
tooltip are drawn at the cursor, arbitrarily far from the part.
The frustum comes from Gribb-Hartmann row arithmetic on
projection * view, deliberately not from mat4_inverse -- that function
had a mistyped index in all sixteen cofactors until
|
|||
| 42b1e7152a |
docs(cad): merge a second render review into the plan, and correct the hash both reviews got wrong
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
A second optimisation plan arrived (frustum culling, geometry merging, GPU instancing, octree/LOD). Rather than run two plans, every claim in it was checked against the tree at |
|||
| 14aa0d5017 |
perf(cad): measure what a frame submits — Phase 0 of the render plan
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
Phase 0 of REVIEWS/CAD_RENDER_OPTIMISATION_PLAN.md. No optimisation
here; this is the measurement everything after it depends on.
0a first: Makepad does not count draw calls. `Cx::performance_stats` is
`PerformanceStats { last_frame_time, max_frame_times }` — frame times
only. So the seam had to be built.
`render_budget.rs` reports two costs, deliberately not summed:
tessellations CPU calls into tessellate_path_stroke
draw calls GPU submissions
Measured at 1920x1080, now in BENCH_BASELINE.md:
zoomed in (0.2 m grid, 170 lines) 2000 parts -> 2170 tess, 2001 draw calls
zoomed out (5 m grid, 270 lines) 2000 parts -> 2270 tess, 2001 draw calls
The grid column barely moves across a 40x zoom range because the step
adapts — that half is already virtualised. The parts column is every
part, every frame, on screen or not.
**This is not a model of the renderer.** The obvious way to count
submissions is to write a second copy of the loop structure and count
what it would do, which is exactly how the scene-cache benchmarks ended
up timing a function that cannot cache. So `grid_range` owns the
decision and `draw_2d_vector_scene` now drives its loops from it: the
count and the drawing come from one function and cannot disagree. The
~25 lines of nice-number step arithmetic that were inline in the
renderer now live in the pure module, with tests.
11 tests, 100% of the new module, and two of them are there to pin
things people get wrong:
- the 2D scene is ONE draw call regardless of part count, because
DrawVector::end() submits the whole accumulation;
- 3D is one draw call per uploaded part, which is where they multiply.
One test — culling_shows_up_as_fewer_part_tessellations — asserts the
*shape* of Phase 1's improvement before the work starts: parts fall
proportionally, the grid column does not move.
Verified: 1062 lib tests pass, cad_integration 154, cargo fmt clean,
engine coverage 97.20% with every floor met including render_budget at
100%. The benchmark runs host-only under CAD_BENCH=1.
|
|||
| 72b0ce250b |
feat(doc-ui): extract doc module from nigig-build into standalone crate
Move 40+ files (~17K lines) from nigig-build/src/construction_frame/pages/workspace/doc/ to crates/apps/doc/doc-ui/src/. Rewrite internal paths from crate::construction_frame::pages::workspace::doc:: to crate::. doc-ui depends on doc-engine, makepad-widgets, nigig-core, serde, serde_json. nigig-build now depends on doc-ui instead of doc-engine directly. |
|||
| 70bbff7ecb |
fix(cad): the nav pad's zoom buttons were a pixel from their own hit zone
Some checks failed
email.yml / fix(cad): the nav pad's zoom buttons were a pixel from their own hit zone (push) Failing after 0s
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
First test written against the widget layer, and it found something on the way in. The viewport's navigation pad — fit, four pans, zoom in, zoom out — had its layout written twice. `viewport_render.rs` drew each button at `col * (BTN_W + GAP)`. `viewport_input.rs` decided what a click hit with hand-written arithmetic inline in a 630-line event handler: `BTN_W * 3.5 + GAP * 3`. Those agree for whole-numbered columns and disagree at the half column the zoom pair sits in: 3.5 * 24 = 84 drawn, 22 * 3.5 + 2 * 3 = 83 hit-tested. The zoom buttons' clickable area sat one pixel left of the buttons, so their right-hand pixel column did nothing and a pixel of empty space beside them zoomed. `PanRight` was 2px short at its right edge for the same reason. One pixel is not much on its own. The mechanism is what matters, and it is the third instance of it in this module: two copies of one piece of geometry, free to drift, with nothing able to notice. The camera-to-world pair was the first, the scene-cache benchmarks the second. Both callers now read `nav_pad::LAYOUT`. The renderer iterates it; the hit test tests against it; the offsets come from one function. That also turns 88 lines of inline conditionals in the event handler into 32 lines of match, which is a readability win I would not have bothered with on its own. The bounds are now the drawn rectangle exactly — half-open, BTN_W by BTN_H, gaps dead. The old hit zones were 2px larger than the buttons in several places. Being strict is deliberate: a hit area larger than its button is indistinguishable from a misaligned one the next time something looks wrong. 7 tests, 100% of the new module. The one that matters is `drawn_and_hit_zones_agree`: every drawn rectangle must hit-test to its own button at all four corners and the centre. That test fails on the old code, which is the only reason to trust it. Verified with a real compiler, which this environment turns out to have: 1051 lib tests pass (7 new), cad_integration 154 pass, cargo fmt clean, engine coverage 97.16% with every floor met including nav_pad at 100%. |
|||
|
|
b478945c34 |
ci(doc): gate the doc-workspace coverage floor on every push
Some checks failed
email.yml / ci(doc): gate the doc-workspace coverage floor on every push (push) Failing after 0s
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
Adds the doc-workspace-coverage job to the nigig-build workflow, mirroring the CAD gate: checkout, then ./tools/test-doc-workspace-coverage.sh, which installs its own instrumented toolchain into a shell-trap-cleaned temp dir and fails if the total floor (92%) or any per-file floor is not met. The script joins the workflow's push/PR path filters next to tools/test-cad-coverage.sh so edits to the harness itself re-run the gate. The doc README gains the milestone section recording the 28.55% -> 96.76% line measurement, the honest exclusions (widget layer, persistence write-path wrappers, defensive traversal guards) and the behavior pins and defect fixes the drive surfaced. |
||
|
|
949cf24189 |
test(doc): doc-workspace coverage harness with enforced floors
tools/test-doc-workspace-coverage.sh measures line+region coverage of the doc module's pure layer the same way the CAD gate does: it copies the dependency-free sources (advanced_json, crdt_bridge, mobile_gesture, persistence, projection_layout, projection_session, and the collaboration/, editing/, layout/, model/, plugins/ trees) plus tests_pure.rs into a temporary host-only crate with the real module path, satisfies the five makepad-math symbols the pure layer uses through a 30-line makepad-widgets shim, runs the suite under -C instrument-coverage with a toolchain it installs itself, and enforces a total floor plus a per-file floor for every instrumented file. The per-file floors are the point: a lone total waves through the silent loss of one whole file's tests. Measurement moved from a 28.55% line baseline to 96.76% (6170 lines) with the tranche in the parent commit; floors sit a few points under per file, except persistence.rs (55%), whose three write-path entry points write into the host's real application-data directory and are covered through their path-injected seams instead -- the honest exclusions, the exact table, and the two defect fixes this drive surfaced (ReplaceBlockRange validation order, dead RgaText::visit_children) are written down in the module's new COVERAGE.md. Everything the script touches -- pinned toolchain, cargo home, target dir, fetched Makepad tree, profraw data -- lives under one mktemp dir removed by a shell trap on every exit path; nothing lands in the repo or $HOME unless KEEP_COVERAGE=1 is set for a debugging run. DOC_WS_COVERAGE_REPORT_ONLY=1 measures without gating. |
||
|
|
71c31cd19f |
test(doc): host-only suite split + pure-layer coverage tranche
Split the doc module's tests in two so the dependency-free majority
can also run under coverage instrumentation on a host-only crate:
* tests_pure.rs (new) holds every test that needs no Cx -- model,
layout, editing, collaboration, advanced JSON, projection
layout/session, CRDT bridge, persistence seams, mobile gestures --
and is the file tools/test-doc-workspace-coverage.sh copies
byte-for-byte into its harness.
* tests.rs keeps the widget-runtime and boot tests; shared helpers
(projection_table_engine, only_table) live in tests_pure so both
suites use them.
On top of the split, this tranche adds ~80 tests covering the pure
layer's real gaps: every Command apply arm and its inverse (text,
atoms, blocks by stable id, image properties, block ranges, table
cells/rows/columns, merges/splits/restores, node insert/delete/
replace), the DocumentController's CRDT typing lifecycle
(insert/replace/delete ranges, backspace/forward delete, position
sync), remote operation classification
(Applied/Duplicate/Deferred/Rejected), tombstone compaction at a
peer-acknowledged frontier, a two-peer MemoryTransport conversation,
typing coalescing and history limits, the cell-text editing and
multi-line geometry helpers in projection_layout, table cell
cursor/range/merge queries, and the small model/session/selection
behaviour surface.
Two defects found while writing the tests, fixed with pins:
* Command::ReplaceBlockRange validated a caller-supplied block_ids
length AFTER draining blocks and legacy ids out of the document, so
a malformed (remote) command destroyed content before reporting
failure. Validation now runs before any mutation; a test proves a
rejected replace leaves blocks, ids and order untouched.
* model::crdt::RgaText::visit_children was dead code -- a
String-collecting duplicate of visit_atoms with no callers. Removed.
Two semantics that were folklore are now pinned with inline
reasoning: a multi-peer conversation only converges when each peer
owns a distinct document.crdt.local_actor (the two-controller sync
test assigns alice/bob), and a mid-range replace_range_crdt renders
its replacement after the tombstoned subtree it replaced, because
RGA sibling order walks by atom id ("hello" -> "hloY" is asserted,
not assumed).
cargo test -p nigig-build --lib: 1031 passed, 0 failed.
|
||
| ac145bfaab |
test(cad): measure tools.rs, which a false comment had ruled out — 0% to 97.07%
Some checks failed
email.yml / test(cad): measure tools.rs, which a false comment had ruled out — 0% to 97.07% (push) Failing after 0s
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
tools.rs opens with:
Struct definitions stay in mod.rs (they use #[derive] macros that
need the script_mod! context). Only the impl blocks are here.
That is not true, and it is the reason 250 lines of pure tool-state
logic — tool cycling, work-plane mapping, the inclined-UCS maths — had
never been measured or tested. `CadTool`, `WorkPlane`, `AxisLock`,
`DrawingState`, `SnapSettings` and `InclinedPlane` each derive some
combination of Clone/Copy/Debug/PartialEq/Eq and nothing else, and none
is inside the `script_mod!` block.
I found it by asking the compiler instead of grepping. Adding each of the
eleven unmeasured CAD files to the harness one at a time and reading the
errors gives the real dependency, not a guess: tools.rs needed six plain
types; viewport_2d.rs needs `CadViewport` and `Cx`; code_editor.rs needs
`Cx2d` and `DrawStep`. Only the first of those is a documentation
problem rather than a real one. My previous two triage passes used a
grep heuristic and were wrong twice, including about this file.
The harness now mirrors those six declarations, extracted from mod.rs at
run time so they cannot drift, exactly as it already did for ViewMode and
SelectionMode. **No production code moved.** Moving the declarations for
real is a smaller job than the comment implies but not a free one:
DrawingState, SnapSettings and InclinedPlane have private fields that
mod.rs and viewport.rs read directly, so their fields need widening
first. CadTool and WorkPlane are fieldless and could move today. That is
now written in the file for whoever has a compiler for the widget layer.
13 tests, on the properties that break quietly:
- Cycling forward visits all 17 tools exactly once and closes the
ring. `cycle_next` is a hand-written 17-arm match; a duplicated or
skipped arm makes a tool unreachable from the keyboard and nothing
else would notice.
- Backwards is asserted to be the exact inverse, per tool. Shift-Tab
that does not undo Tab reads as "the tool picker jumps".
- Labels must be unique — two buttons reading the same is a UI bug
with no test otherwise — and every tool needs a description.
- `to_kind` maps only the drawing tools; Select, Delete and Measure
must return None or they would create geometry on click.
- `InclinedPlane::from_3_points` produces a unit normal perpendicular
to both edges, and rejects collinear or coincident picks rather than
returning a NaN basis from a zero-length cross product.
- The plane basis is orthonormal in both branches, including the
vertical-normal case that exists because the usual "up" reference is
parallel to the normal there.
Also fixes a real bug in this script's own drift detector: it tested
membership with `case " ${ENGINE_FILES[*]} "`, and `[*]` joins on the
first character of IFS, which this script sets to a newline. The pattern
could never match, so the note fired for every non-widget file. It was
right about tools.rs by accident.
Floor: tools.rs 95. Total unchanged at 97.14% over a larger denominator.
Verified: 568 tests green, every floor met, hermetic run clean.
|
|||
| e46b2c504a |
fix(cad): the scene-cache benchmarks were measuring a function that cannot cache
Some checks failed
email.yml / fix(cad): the scene-cache benchmarks were measuring a function that cannot cache (push) Failing after 0s
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
`REVIEWS/PAY_CAD_IMPLEMENTATION_STATUS.md` has carried the same CAD entry through ten tranches — "unchanged", blocked on "no Cargo toolchain is available in this execution environment to run the required tests/profiles". `profile_benchmarks.rs` imports nothing from Makepad but the math types, so it builds in the same host-only harness the coverage run already uses. `CAD_BENCH=1 ./tools/test-cad-coverage.sh` runs all 16, release, no desktop, self-cleaning. Running them found the drift they exist to catch. `bench_scene_cache_hit_vs_rebuild` reported **1.2×** against the **488×** recorded in BENCH_BASELINE.md, and `bench_scene_cache_scaling` reported 1× at every part count with the warm read scaling linearly — 3.2 µs at 10 parts to 64 µs at 500. That reads as a catastrophic cache regression. It was not. Both called `SceneCache::scene(&[CadNode])`, which is documented as always rebuilding: it takes a bare slice, so it has no generation to compare against and cannot cache. The editor's caching entry point is `scene_for(&PartsStore)`. When the generation-tracked store landed in Phase 5.1 these two benchmarks were not moved with it, so their "warm" sample was a second full rebuild and the printed speedup was allocator noise. Nobody saw it because the benchmarks had not been runnable since. Repointed at `scene_for`, they reproduce the checked-in baseline on different hardware: cold 24.6 µs / warm **48 ns**, **512×** against the recorded 488×, and the warm read is flat at ~55 ns from 10 parts to 500. `bench_scene_cache_hit_vs_rebuild` now asserts `Arc::ptr_eq` across its two samples, so it fails loudly instead of quietly timing two rebuilds if it is ever pointed at a non-caching path again. `SceneCache::scene()` itself is untouched. I started to delete it as a "cacheless method on a cache" and stopped: its docstring says exactly what it does and why, and nine tests use it for precisely that case. The benchmarks were wrong, not the API. Verified: the 16 benchmarks run and reproduce the baseline; the default coverage mode is unchanged at 97.14% with every floor met. |
|||
| 33ef24cee5 |
refactor(cad): one screen-to-world path, not two
Some checks failed
email.yml / refactor(cad): one screen-to-world path, not two (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
viewport.rs carried two independent implementations of the same geometry. `screen_to_ray_3d` and `screen_to_world_3d` derive the camera basis from yaw, pitch, distance and a 42-degree fov; `camera_eye` and `unproject_point` did the same job by inverting `last_view` and `last_proj`. The matrix pair was dead — nothing in the workspace called either of them, and no script binding registers them by name. Two implementations of one piece of geometry, one of them never executed, is exactly how axis conventions drift apart. The evidence is in the deleted code: `camera_eye` carried its own spherical "fallback" that was a copy of `compute_eye`, complete with a "FIXED: was +cp*cy (must match makepad XR convention)" note about a convention the live copy had already been corrected for. A second copy of a convention is a second place to forget to fix it. So the dead pair goes, and a breadcrumb comment in its place says where screen-to-world actually lives — the question someone will have when they find `mat4_inverse` and wonder why nothing calls it. `math::mat4_inverse` stays. It is correct and covered now, and using the matrices the renderer actually drew with is the better way to unproject than re-deriving the camera basis from Euler angles — that is a real improvement for whoever wants it, and they should start from a version that works. Its doc comment no longer claims callers it does not have. VERIFICATION, stated plainly: `cargo check -p nigig-build` needs the Makepad desktop stack and does not run in the environment this was written in. What did run: rustfmt parses both files (a syntax error would be a parse failure, not a diff); a brace/paren delta count over the deletion (10 opens, 10 closes; 31 parens each way); a repo-wide grep for both names across every file type, which finds only comments; and the engine coverage suite, unchanged at 97.14% with every floor met. The compile is gated by full-crate-check in CI, which is where a missed reference would surface — loudly, and immediately. |
|||
|
|
dd8cc17b75 |
fix(doc): re-float the clipboard menu when a selection-handle drag ends
Some checks failed
email.yml / fix(doc): re-float the clipboard menu when a selection-handle drag ends (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
On mobile the native menu floated at long-press word-select (or select-all) but dragging either handle afterwards re-anchored nothing, leaving the platform toolbar over the previous word — or already dismissed — once the selection had moved. The gesture router's end() only distinguishes PendingLongPress, so the Stop arm now samples the router state first: when the ended gesture was AdjustingStartHandle or AdjustingEndHandle and the session is in Edit mode, the menu re-floats on lift-off through the same cx.show_clipboard_actions request the long-press arm sends, with rect = the adjusted selection's handle union (the existing clipboard_menu_rect). Mid-drag stays quiet (the TextInput cadence DEVICE_VERIFICATION 3.3 documents) and View mode keeps handle drags as pure highlight/merge surface. Tests (2 new): a runtime drive of long-press 'hello' -> end-handle drag onto 'w' in 'world' -> lift-off asserts no request mid-drag, a fresh request on Stop whose rect covers more than the stale word rect, and the focus atom on the dragged-to glyph; the View-mode twin asserts the span adjusts while clipboard_menu stays empty. DEVICE_VERIFICATION gains row 3.6 for the hardware pass. |
||
| 4ea1224e49 |
test(cad): actually exercise the GLB parallel path, 94.83% -> 98.65%
Some checks failed
email.yml / test(cad): actually exercise the GLB parallel path, 94.83% -> 98.65% (push) Failing after 0s
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
Correcting my own test from two commits ago. `build_glb` only reaches
rayon at 32 or more geometric nodes -- below that it runs an ordinary
iterator. Every test in the file used one or two nodes, so:
- the `par_iter()` arm, the reason rayon is a dependency at all, had
never executed; and
- the test named "the sequential fallback matches the parallel
builder" was comparing `build_glb`'s SEQUENTIAL branch against
`build_glb_sequential`. Two sequential paths. It would have passed
with the parallel arm deleted.
The coverage report is what showed it: those lines stayed red after a
commit whose message claimed to cover them.
Three tests:
- 40 nodes, crossing the threshold, asserted byte-identical to the
sequential builder and with mesh names still in order.
`par_iter().filter_map().collect()` preserves order; `par_bridge`
or a collect into a map would not, and the symptom is a model whose
parts are labelled with each other's names.
- The sequential builder walks a SceneVisitor whose per-variant arms
are separate code from the parallel path's `collect_node`. Seven
variants through it, asserting one mesh each.
- Nodes that are geometric but mesh to nothing (two empty CSG
results) hit the third error arm, on both paths. Without it the
exporter writes a GLB with an empty buffer, which a viewer opens as
a blank stage and the user reads as a successful export.
Floor: arch_gltf 92 -> 97.
Verified with: ./tools/test-cad-coverage.sh (555 tests green, total 97.14%)
|
|||
| 723fe019d0 |
test(cad): the store's generation contract, the STL trait impl, and two NaN guards
Some checks failed
email.yml / test(cad): the store's generation contract, the STL trait impl, and two NaN guards (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
Mop-up of three files whose remaining gaps were small but not empty.
scene_holder 96.16 -> 100.00%, arch_stl 96.83 -> 98.88%,
construction_geometry 95.08 -> 95.88%.
scene_holder — the generation counter is the whole reason PartsStore
exists: it moves on its own so `SceneCache::scene_for` can tell whether
its cached scene is stale, instead of trusting every caller to remember
`mark_dirty()`. That contract is per-method and nothing checked it:
- Reads must NOT bump. Eight of them (len, as_slice, iter, get,
find_by_raw_id, index_of_raw_id, is_empty) asserted against one
generation snapshot. A read that bumps rebuilds the scene every
frame -- slow, and invisible.
- `get_mut` bumps only on a hit. Bumping on a miss invalidates the
cache for a lookup that changed nothing.
- `iter_mut` bumps unconditionally, before it knows whether the
caller writes. That is the deliberate conservative choice that
replaced the `as_mut_vec()` escape hatch, and it is now pinned so
nobody "optimises" it into a lie.
- The pairing itself: an unchanged store returns the same Arc, a
bumped one rebuilds and the rebuilt scene carries the edit.
- `PartIdAllocator::default()` must agree with `new(1)`. Defaulting
to 0 would hand out an id that reads as "no node".
arch_stl — only `build_stl` was covered, so the `Exporter` impl (the
path the export buttons and the async worker take) had never run. Both
arms now write the same bytes, both report a failed write, and a group
node contributes nothing an empty scene would not: meshing it would add
an empty solid and shift every later vertex index.
construction_geometry — the two non-finite guards in
`snap_to_polar_angle` and `normalize_angle_signed`. `rem_euclid` on an
infinity is a NaN, so without them an infinite drag delta becomes a NaN
heading and every vertex after it is NaN. Also the documented wrap-round
contract at the boundary: 370 degrees behaves as 10, -30 snaps to -45
rather than 315, and pi stays pi because the range is (-pi, pi].
Its remaining 20 uncovered lines are `other => panic!(...)` arms inside
existing tests. Those only execute when a test fails, so they are
uncoverable by construction rather than untested.
Floors: construction_geometry 92 -> 95, arch_stl 94 -> 98,
scene_holder 93 -> 99, total 95 -> 96.
Verified with: ./tools/test-cad-coverage.sh (552 tests green, total 96.86%)
|
|||
|
|
228bc2c81f |
ci(doc-engine): gate the engine coverage, and note it in the doc README
Some checks failed
email.yml / ci(doc-engine): gate the engine coverage, and note it in the doc README (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
doc-engine / engine (push) Has been cancelled
doc-engine / coverage (push) Has been cancelled
doc-engine / consumer (push) Has been cancelled
New coverage job runs tools/test-doc-engine-coverage.sh on changes to crates/apps/doc/**, the script itself, or the workflow. A coverage number nobody gates goes down; the floors (total plus per-file) are the enforcement. The doc workspace README records the milestone and the two CRDT-tolerance behaviors the new tests pin. |
||
| aad2a20d43 |
test(cad): cover the PDF plan projection, 75.92% -> 88.99%
Some checks failed
email.yml / test(cad): cover the PDF plan projection, 75.92% -> 88.99% (push) Failing after 0s
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
The last of the four exporters with the same gap: the arch projector
classifies each node by LAYER NAME and then by geometry, and only the
wall path had ever run. Columns, beams, spheres, generic blocks,
polygons, the 2-D primitives and CSG results all reached their own
`make_*` and none of them were executed, along with both public entry
points.
10 tests:
- The plan projection negates Z so north is up. One line, and a sign
error there mirrors the entire drawing.
- Cylinders become Columns and spheres become Spheres, with centre,
radius and height asserted, and the label prefix checked -- the
labels carry a per-type counter that the drawing schedule reads.
- A box on an unregistered layer falls back to a generic Block rather
than vanishing. That fallback is what keeps an unclassified part on
the drawing.
- A beam keeps length on size.x, plan width on size.z and thickness
on size.y. Swapping any two produces a plausible-looking beam of
the wrong shape.
- Polygons and extruded polygons are drawn as their bounding box
centred on the polygon's own centre, not the node origin -- the
node is at (2, 3) and the triangle's centre is offset from it, so
the test would pass either way if it only checked the size.
- An empty vertex list emits nothing, rather than a zero-by-zero
block at the plan origin.
- `export_scene_to_pdf` writes a real `%PDF-` file into a directory
it had to create, and reports a path it cannot create.
The tolerances in this module are 1e-6 rather than 1e-9 on purpose:
every dimension crosses f32 to f64 on the way in, and 0.3f32 as f64 is
0.30000001192092896. The first draft used 1e-9 and failed on the beam.
Floors: arch_pdf 72 -> 86, total 94 -> 95. The remaining 152 lines are
the printpdf emitter itself -- page furniture, dimension strings and
title-block layout, whose output is only meaningfully checked by
opening the file.
Verified with: ./tools/test-cad-coverage.sh (540 tests green, total 96.53%)
|
|||
| 5e864498d5 |
test(cad): cover the GLB export entry points and every solid it collects, 75.48% -> 94.83%
Some checks failed
email.yml / test(cad): cover the GLB export entry points and every solid it collects, 75.48% -> 94.83% (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
Same shape of gap as the SVG exporter, one file over. The mesh
collector had an arm per solid and only boxes were ever walked through
it; `scene_to_glb`, `export_scene_to_glb`,
`export_scene_to_glb_with_cache` and `build_glb_sequential` -- every
public entry point except the one the trait impl uses -- were at zero,
along with both `From` conversions on the error type.
8 tests:
- Nine solids exported one at a time, each asserted to produce a
structurally valid GLB: the "glTF" magic, version 2, and a declared
length that matches the file. A viewer rejects the file outright if
any of those disagree, so checking "some bytes came back" would not
have been worth writing.
- The sequential fallback is asserted byte-identical to the parallel
builder. It is documented as the path for environments without
rayon; if it drifts, that fallback silently exports something else
and only those environments see it.
- An empty scene and a groups-only scene are both refused, with the
two distinct messages. A GLB that opens to an empty stage is worse
than a refusal, because the user reads it as "the export worked".
- `export_scene_to_glb` creates the directory it was pointed at (the
user picks the path, its parent may not exist), the shared-cache
variant writes identical bytes, and both report a path they cannot
create instead of dropping the export.
- The error type's Display, plus its io and serde_json `From`
conversions -- those exist so `?` works inside the export path, and
an unexercised conversion is a `?` that fails to compile the day
someone needs it.
Floors: arch_gltf 72 -> 92, total 93 -> 94.
Verified with: ./tools/test-cad-coverage.sh (530 tests green, total 95.42%)
|
|||
| e16a6da5f5 |
test(cad): cover the real command context and the undo-stack housekeeping, 87.63% -> 96.23%
Some checks failed
email.yml / test(cad): cover the real command context and the undo-stack housekeeping, 87.63% -> 96.23% (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
The undo/redo tests all ran against a mock. The mock keeps its own Vec,
so `CadCommandCtx` -- the implementation the editor actually uses --
had two methods that no test had ever called: `update_node`, the
in-place property edit, and `insert_node_at`, the undo of a delete.
`UndoRedoStack::clear`, its Debug impl, and the describe/as_any pair on
half the command types were also at zero.
12 tests against the real context, with a real PartsStore:
- `update_node` edits in place, bumps the store generation, and does
NOT reorder the list. Order is what the layer panel and the draw
order read; the same class of reordering defect is already called
out in the mock's own comment.
- `update_node` on a missing id reports NodeNotFound and does not run
the edit closure -- otherwise a stale selection edits whatever node
happens to be in that slot.
- `insert_node_at` puts a deleted node back at its recorded index,
not on the end, and clamps an out-of-range index instead of
panicking. The index is captured before the delete and other
commands may have shortened the list since.
- DeleteNode and CreateNode are round-tripped through the real
context, including DeleteNode's no-recorded-index arm (appends) and
CreateNode's fallback from `assigned_id` to the snapshot id.
Plus the trait and stack housekeeping:
- The `Command` defaults: the generic "command" label, and
`can_merge` returning false. A default of true would silently
collapse unrelated undo steps.
- `clear()` empties both stacks. The editor calls it when a document
is closed; an entry surviving into the next document applies an
edit to the wrong model.
- The Debug impl prints depths and asserts the command list is NOT
dumped -- a derived Debug over two stacks of boxed trait objects
would put the whole edit history in a log line.
- Every command type's describe/as_any, including that two commands
with identical field shapes do not downcast into each other. That
downcast is what `can_merge` runs on; a wrong one turns a drag into
one undo entry per frame.
Floors: commands 85 -> 94, total 92 -> 93.
Verified with: ./tools/test-cad-coverage.sh (523 tests green, total 94.31%)
|
|||
| 44bf7da725 |
test(cad): cover the shapes the SVG exporter never drew in a test, 82.48% -> 99.02%
Some checks failed
email.yml / test(cad): cover the shapes the SVG exporter never drew in a test, 82.48% -> 99.02% (push) Failing after 0s
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
Only boxes were exercised. Cylinders, spheres, circles, arcs, polygons,
extruded polygons and CSG results all had their own arm in the SVG
visitor and not one of them was executed — 110 uncovered lines, in the
exporter that produces the construction drawing.
That is the worst shape for an exporter bug: a part whose arm is wrong
does not fail anything, it just is not in the drawing. Nothing is red,
the file opens, and the column is missing.
13 tests:
- Every drawable variant is exported on its own and must produce
exactly one path. Nine variants, nine assertions.
- A round outline has one point per segment, and a sphere is drawn
from segments_u, not segments_v. Both show up visually as a column
faceted in the wrong axis rather than as an error.
- An arc is sampled inclusively across its 32 segments (33 points) so
it closes on the end angle instead of stopping a step short, and a
half sweep must not return to its start.
- A polygon with two vertices, and an empty CSG result, add no path.
An empty `points=""` renders as a stray dot in some viewers.
- The `Exporter` impl itself: the cacheless `export`, the cached one
(asserted byte-identical), and the write-failure arm, whose message
is what the status label shows. Only `build_svg` was covered
before, so a broken `export` would have shipped.
- A 90 degree yaw must change the projected outline of a polygon.
The box arm had rotation covered; the polygonal and round arms use
a different projection helper and had none.
Floors: arch_svg 79 -> 97, total 89 -> 92.
Verified with: ./tools/test-cad-coverage.sh (510 tests green, total 93.44%)
|
|||
| a82916b006 |
test(cad): cover the scene-graph builder API, 81.73% -> 98.53%
Some checks failed
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
email.yml / test(cad): cover the scene-graph builder API, 81.73% -> 98.53% (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
cad_scene.rs is the type every other CAD file is written against, and
388 of its lines had never been executed. The gap was not in exotic
corners -- it was the fluent builder the whole editor and the script VM
construct scenes through. `NodeBuilder`'s setters, `SceneBuilder`'s
starters and domain builders, `push_raw`, `CadTransform`'s helpers, the
2-D solids' size/set_size arms, `ParamHash` over half the variants,
`walk_scene`'s dispatch, and the `Exporter` default methods were all at
zero.
32 tests, grouped by what they protect:
- The setters are checked for what they must NOT touch as well as
what they set. `.cube().radius(9.0)` has to be a no-op, not a
silent solid swap; `.rotate_y(30).rotate_y(15)` has to be 45
degrees, because every one of these helpers is additive and a
helper that assigned instead would drop the earlier call.
- The domain sugar is pinned to its documented axes: length/width to
size.x, domain_height to size.y, thickness/depth to size.z. Getting
one onto the wrong axis gives a wall 0.2 m long and 6 m thick,
which reads as a modelling mistake rather than a code one.
- The six domain builders are checked for layer, name and their
documented default colour. Asserting the colour rather than "not
the default material" is deliberate and was found the hard way:
Column's grey IS the default colour, so it correctly shares the
default material instead of registering a duplicate.
- `set_size` is checked on every parametric solid. It is what the
properties panel calls, and a missing arm is a control that does
nothing -- the same class of defect the by-value-getter CI gate
already guards.
- `size()` on a CSG or extruded solid is checked against a real mesh
bounding box, including the empty-result case. That arm used to
return a hardcoded 1x1x1, which made those parts unpickable outside
a 1 m box at their origin.
- `ParamHash` is checked to move for every field of the 2-D and
section variants. It keys the mesh cache AND the viewport's GPU
buffers, so a field it does not hash is an edit that leaves stale
geometry on screen.
- `walk_scene` is checked to route all twelve `CadSolid` variants to
their own callback, in order, with `leave_node` always firing. The
exporters are all visitors: a variant landing in the wrong arm is a
part that silently vanishes from the STL, the SVG or the PDF. A
visitor overriding nothing is walked too, so the trait's default
bodies are executed rather than assumed.
- `export_to_vec`, `export_with_cache` and `spawn_export` -- the
default methods an exporter gets for free, all on the async export
path -- are driven through a counting stub, with the worker thread
joined so the callback assertion is deterministic.
Floors raised to lock it in: cad_scene 78 -> 96, total 85 -> 89.
Remaining 44 lines are small accessors and defensive arms.
Verified with: ./tools/test-cad-coverage.sh (499 tests green, total 92.44%)
|
|||
|
|
d62cc13d34 |
style(nigig-build): cargo fmt the two test targets left unformatted
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
email.yml / style(nigig-build): cargo fmt the two test targets left unformatted (push) Failing after 0s
tests/ui.rs and tests/cost_estimator.rs drifted out of rustfmt shape in the recent feature/merge series, failing the whole-crate fmt gate (cargo fmt -p nigig-build -- --check). Mechanical reformat only. |
||
|
|
ff0cba1b80 |
fix(project): replace retired SpreadsheetGrid::select_cell with set_selection_pair
spreadsheet-ui |
||
|
|
5e5adf962d |
fix(doc): boot the CRDT editor with content and migrate persistence to the app-data store
The Android APK (pageflipnav) booted the doc workspace to a blank page.
Two compounding causes, both invisible to sandbox gates:
- CrdtDocEditor (the active editor since the navigation switch) had no
boot init: it starts from DocumentController::default() and only the
legacy DocEditor seeded the showcase document behind its initialized
gate. The first event on a factory-fresh editor now runs
init_document: load the on-disk save when it decodes as #MP_CRDT_V1
wire (initial_document_source gates that so classic-format saves stay
with the legacy workspace's first-edit migration), otherwise
seed_demo_doc builds a CRDT mirror of demo_doc_blocks() -- styled
headings, accent runs, divider, image node, the 4x3 table with bold
header, and the closing hint. set_engine flips the same flag so a
host-installed document is never overwritten.
- persistence.rs resolved its save file under
env!("CARGO_MANIFEST_DIR"), baking the build machine's absolute
source path into the binary; on device that path does not exist, so
Open read nothing and Save wrote nowhere (the errors were swallowed),
and on desktop the app polluted its own checkout. Writes now go only
to app_data_dir()/nigig_build_store/generated/current.doc.json (the
crate-wide convention the CAD store already uses); reads keep a
one-way fallback to the legacy source-tree file so an unreplicated
developer save is honored once. Boot and migration emit [DOC_TRACE]
lines so a device logcat session names the branch that fired.
Tests (8 new): boot-source gate (CRDT wire boots verbatim; classic JSON
and None route to the demo seed), runtime boot on first event
(source-agnostic non-empty projection + flag), host-installed-engine
no-overwrite guard, full structural assertion of the seeded showcase,
and four temp-dir persistence tests (round trip, store-beats-manifest
precedence, manifest fallback, empty-file rejection).
DEVICE_VERIFICATION.md gains the matching section-9 hardware rows (9.0
fresh-install demo boot, 9.3 classic-save coexistence).
|
||
| d15a034797 |
test(cad): cover the async export path and the model-name env read
Some checks failed
email.yml / test(cad): cover the async export path and the model-name env read (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
exporters.rs 76.30% -> 91.17%, constants.rs 82.69% -> 97.30%.
`spawn_export_to_target` was 0% -- the entire function. It exists
because every export used to serialise on the UI thread into a fixed
path, so a 1,000-part GLB froze the editor and the second export of a
session destroyed the first. The replacement had never been executed by
a test: not the worker thread, not the BufWriter flush, not the callback.
Four tests, driven by a stub Exporter over an empty scene, each blocking
on the callback through a channel so the assertion is that `on_done`
actually fires on the worker thread:
- success: the bytes land at the path, and the status message names
the byte count and the destination. The old fixed-path exports had
nothing to assert here -- the destination was not a parameter.
- exporter failure: reported as "export failed: ...", and NO file is
created. A half-written export that reports success is worse than
no export.
- undeliverable: parent is a regular file, so create_dir_all fails
and the message says so.
- a directory in the file's place: the other side of the
create_dir_all guard, where the write itself fails.
Still uncovered in exporters.rs: the ExportTarget::Prompt arm, 28 lines.
It raises a native save dialog; there is no windowing system in a
coverage run and the harness's picker stub deliberately refuses rather
than faking a save, so those lines are reported as uncovered instead of
being reached by a test that proves nothing.
constants.rs: local_openai_model was the one endpoint-configuration
reader with no test, while local_openai_url next to it had five. A blank
model name now has to be None -- passing "" to the endpoint produces a
rejected request that surfaces to the user as an AI failure rather than
as missing configuration.
Verified with: ./tools/test-cad-coverage.sh (466 tests green)
|
|||
| 34d47f4479 |
test(cad): cover persistence.rs, 0.00% -> 94.51% of lines
Some checks failed
email.yml / test(cad): cover persistence.rs, 0.00% -> 94.51% of lines (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
persistence.rs owns every byte the CAD editor writes: the saved script,
the baked OBJ mesh, the thread-local slot the script VM uses to hand a
Solid back to the UI, and the pending-image mutex. It had no tests. Not
low coverage -- zero.
It could not have had any. `save_cad_state` and `load_saved_cad_script`
resolve their directory through `cad_data_dir()`, which is the real
per-user application data directory. A test that called them would write
into the developer's (or the CI runner's) actual data dir, and two tests
would fight over the same file. So the save/load pair is split:
save_cad_state_in(dir, source, solid)
load_saved_cad_script_in(dir)
with the existing public functions delegating to them through
`cad_generated_dir_path()`. No caller changes, no behaviour changes --
viewport.rs, workspace.rs and workspace_actions.rs keep calling exactly
what they called before.
14 tests, on the failures rather than the happy path:
- A save that cannot create its directory returns the "could not
create generated directory" error. This is the path that used to be
`.ok();` at the call site, which is how a "Saved" label appeared
over a write that never landed.
- A failed OBJ write still leaves the script on disk, and the test
asserts the script is readable back afterwards. The write order is
load-bearing: losing the baked mesh costs a rebuild, losing the
source costs the user's session.
- An empty or whitespace-only script file loads as None, not as
Some(""). Some("") would open the editor blank and then overwrite a
script the user still had.
- The script-output slot must empty on take. A stale Solid re-applied
on the next tick would silently undo whatever the user did in
between.
- The generated paths are asserted to hang off the runtime data dir
and to contain no build-time source path -- the CI gate for that
rule greps for one macro, this pins the actual result.
Uncovered: 6 lines, the two public wrappers. Calling them means writing
to the real data dir, which is the thing this commit is avoiding.
Verified with: ./tools/test-cad-coverage.sh (459 tests green)
|
|||
| 2ea5a7424e |
fix(cad): mat4_inverse was wrong for every matrix that rotates and translates
Some checks failed
email.yml / fix(cad): mat4_inverse was wrong for every matrix that rotates and translates (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
3-D picking has been unprojecting clicks to the wrong world point. The
coverage run in the previous commit left seven lines uncovered -- the
success tail of mat4_inverse -- and the round-trip test written to reach
them failed on element 12.
mat4_inverse is a cofactor expansion transcribed from the standard MESA
gluInvertMatrix. Comparing all sixteen expressions term by term against
the reference, EVERY ONE of them had at least one mistyped index:
inv[0] a[9]*a[11]*a[14] should be a[9]*a[7]*a[14]
inv[12] a[8]*a[10]*a[13] should be a[8]*a[6]*a[13]
inv[13] a[8]*a[10]*a[13] should be a[8]*a[2]*a[13]
inv[14] a[0]*a[7]*a[13] should be a[0]*a[6]*a[13]
inv[14] a[4]*a[7]*a[13] should be a[4]*a[2]*a[13]
... and one each in the other eleven.
The wrong terms all carry a[3], a[7], a[11] or a[15] -- the bottom row.
For a pure translation or a pure rotation those are 0, 0, 0, 1 and the
mistyped products cancel, which is why the function looks correct in
isolation and why nothing caught this. It stops cancelling the moment a
matrix rotates AND translates.
Which is what the two callers pass in:
- CadViewport::camera_eye inverts self.last_view.
- CadViewport::unproject_point inverts self.last_proj, whose element
11 is -1 for a perspective camera, and then self.last_view.
Measured on a view matrix with a 35 deg yaw and eye (3, -1, 2), the old
code's inv * m came back with 0.4698 and -0.7988 in the translation row
instead of zero: a click resolved to a point roughly one unit away from
where the user clicked, growing with camera distance. Selection, snap
and the measure tool all read that point.
Fixed by transcribing the reference again, this time verified: the tests
assert inv*m AND m*inv against the identity for a translation, a
rotation, translate*rot_y, translate*rot_zyx, a perspective matrix, an
orthographic matrix, and a dense matrix with no zero entries -- the last
because a wrong index cannot cancel when nothing is zero.
math.rs is now 99.60% of lines. The three remaining are the
`det.abs() < 1e-8` early return's own arm, covered by
mat4_inverse_of_a_singular_matrix_is_none but not attributed to it.
Verified with: ./tools/test-cad-coverage.sh (445 tests green)
|
|||
| 500489c2f0 |
test(cad): cover math.rs, 20.40% -> 99.00% of lines
Some checks failed
email.yml / test(cad): cover math.rs, 20.40% -> 99.00% of lines (push) Failing after 0s
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
math.rs had no tests at all. Every other engine file in the CAD module
carries its own #[cfg(test)] block; this one -- the file that decides
where a click lands in 3-D, whether a point is inside a picked polygon,
and how a part's model matrix is built -- had none, and the coverage
harness added in the previous commit put a number on it: 20.40%.
39 tests, written against the behaviour that is easy to get wrong rather
than the happy path:
- The two normalize functions disagree on purpose. DVec3::normalize
returns -Z for a degenerate vector, vec3_normalize returns zero.
Both are pinned, because "fixing" either to match the other would
change picking behaviour silently.
- point_in_polygon is exercised on a concave L-shape, not just a
square. The picking path projects a bounding box to screen space and
can produce a concave outline; a convex-only test passes on a
ray-casting implementation that is broken for exactly that case.
- point_on_segment_nearest is checked past both endpoints, where the
projection parameter is clamped, and on a zero-length segment, where
the 1e-12 guard is the only thing between the caller and a NaN.
- ray_triangle_intersect is checked on each rejection branch
separately: parallel, u < 0, v < 0, u + v > 1, and a triangle behind
the origin.
- ray_aabb_intersect is checked from outside, from inside (where it
returns the exit parameter, not the entry), behind the ray, parallel
to a slab both inside and outside it, with a negative direction
component (the t1/t2 swap), and on a diagonal miss -- which is the
only way to reach the `tmin > tmax` return, since an axis-aligned
miss leaves through the parallel-slab branch first.
- segment_intersection is checked parallel, crossing, and crossing
off the end of one segment and of both.
Remaining uncovered: 7 lines, the success tail of mat4_inverse. The next
commit reaches them, and finds out why they were never reached.
Run: ./tools/test-cad-coverage.sh
|
|||
|
|
34fecf1924 |
build: pin every git dependency to a full 40-character SHA (Phase 0.2)
The repo has a CI gate requiring full-length revs, added deliberately in |
||
| ce0eaae935 |
fix(build): bump makepad pin to ecf5a572, restoring the test feature
Some checks failed
repo hygiene / hygiene (push) Has been cancelled
nigig-map / test (push) Has been cancelled
Payment domain, storage, platform and UI / isolated-payment-tests (push) Has been cancelled
Payment domain, storage, platform and UI / payment-ui-tests (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
|
|||
| 86c9595729 |
chore: update makepad fork to latest upstream/dev (abd70f4)
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
nigig-map / test (push) Has been cancelled
Payment domain, storage, platform and UI / isolated-payment-tests (push) Has been cancelled
Payment domain, storage, platform and UI / payment-ui-tests (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
Updated makepad fork to include all latest APIs needed by map widget: - pack_vector_vertices and VECTOR_PACKED_FLOATS_PER_VERTEX - TileArchiveReader for MKMap archive support - get_tile_decoded method on MbtilesReader - set_trust_fill_winding and fill_fringe_into on Tessellator - retain_queued method on TagThreadPool - set_camera_delta method on DrawRotatedText This resolves all compilation errors in the map widget code. |
|||
| c66ffcb303 |
test: add comprehensive CAD UI tests for all implemented features
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
Added 50+ UI tests covering: - Toolbar buttons (tools, export, zoom, rotation, grid, visibility) - Tool selection via click and keyboard - Drawing creation (rect, circle, wall, column, beam) - Undo/redo roundtrip - Selection and deletion - View manipulation (plane toggle, rotation, zoom, workplane rotation) - Snap/ortho/polar toggles - Grid and reference plane buttons - Export buttons (STL, SVG, PDF, OBJ, 3D, CLI) - PDF preview tab switching - Code editor visibility and content - Cost estimation screen - AI pane widgets - File operations - Splitter toggles - Properties panel - Status label text verification - Mobile editor tabs - All CAD tool buttons (arc, polyline, area, quad, polygon, triplane, extend, chamfer) - Render mode dropdown - View toggle button |
|||
| 9d647cec8c |
build(deps): bump makepad fork rev to 5efe6e24c (makepad-test enabled)
Some checks failed
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
nigig-map / test (push) Has been cancelled
Payment domain, storage, platform and UI / isolated-payment-tests (push) Has been cancelled
Payment domain, storage, platform and UI / payment-ui-tests (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
doc-engine / engine (push) Has been cancelled
doc-engine / consumer (push) Has been cancelled
All 35 Cargo.toml pins move from d82756a to 5efe6e24c on the gitdab fork (portallist base + makepad_test Android adb / standalone terminal wiring). Lockfile regenerated; pdf crates compile against the new rev. |
|||
| 8fe7db2621 |
fix: update SpreadsheetGrid selection API in project/mod.rs
Replace deprecated selection_anchor/selection_head field access with set_selection_pair() method call after spreadsheet-ui refactor. |