Skip to content

Establish the workspace and the demo harness contract (1.1) - #7

Merged
leynos merged 22 commits into
mainfrom
1-1-establish-the-workspace-and-the-demo-harness-contract
Jul 26, 2026
Merged

Establish the workspace and the demo harness contract (1.1)#7
leynos merged 22 commits into
mainfrom
1-1-establish-the-workspace-and-the-demo-harness-contract

Conversation

@leynos

@leynos leynos commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

Delivers roadmap step 1.1 — both tasks 1.1.1 (workspace crate layout)
and 1.1.2 (shared demo harness) — per the ExecPlan at
docs/execplans/1-1-establish-the-workspace-and-the-demo-harness-contract.md
(now Status: COMPLETE, with full progress notes, decision log, and
retrospective).

Workspace (1.1.1)

  • Converts the repository into a six-member Cargo workspace: the root
    package thysalion as composition root plus crates/{world,sim, knowledge,presentation,harness,demos}.
  • Plane crates are documented stubs carrying their §6.1 authority rows;
    thysalion-world is the dependency sink.
  • Workspace-level lints ([workspace.lints]) preserve the strict Clippy
    policy across every member; [workspace.dependencies] is the single
    version source (Bevy 0.19 with a curated feature list that needs
    zero extra system packages in CI).
  • Release builds are scoped with -p thysalion so demo crates never
    enter the cross-compilation graph, guarded by a workflow-shape test.

Demo harness (1.1.2)

  • thysalion-presentation owns the pure camera contract: Quadrant
    (four yaw quadrants, cyclic) and ZoomBounds (validated, clamping).
  • thysalion-harness is a two-plugin contract: HarnessCorePlugin
    (headless-safe: rig state, input mapping, diagnostics registration,
    synthetic-input expiry) and DemoHarnessPlugin (camera entity,
    F3 diagnostics overlay, F12 screenshots).
  • demo-empty opens a window, renders a lit ground plane, and reports
    diagnostics. Run it with make demo.
  • Behavioural coverage: four rstest-bdd 0.6.0-beta3 scenarios drive the
    harness through a Bevy HarnessAdapter under MinimalPlugins
    (38 tests green overall).

Documentation

ADR-005 (workspace crate layout), a rewritten repository-layout.md,
demo-harness sections in the developers' and users' guides, and roadmap
ticks for 1.1.1/1.1.2.

Verification

  • make check-fmt, make lint (rustdoc + Clippy + Whitaker dylint),
    make test (38/38), make spelling, make markdownlint, and
    make nixie all pass locally before each commit.
  • Windowed smoke run under WSLg: the window opens and renders via
    software Vulkan without panicking.
  • CodeRabbit agent review of the full branch: zero findings.
  • Still wanted from a human reviewer: interactive feel of Q/E rotation
    and zoom bounds, F3 overlay values, and an F12 screenshot artefact
    (this host has no GPU passthrough).

leynos added 2 commits July 24, 2026 18:06
Plan roadmap step 1.1: converting the single-crate repository into a
Cargo workspace with one crate per architectural plane plus `harness`
and `demos` crates, and implementing the shared demo harness proven by
a `demo-empty` binary.

The plan was revised after a six-lens design review before any
implementation. Notable outcomes:

- Camera contract types (`Quadrant`, `ZoomBounds`) live in
  `thysalion-presentation`, not the harness, so the shipping
  presentation plane never depends on demo scaffolding.
- The harness is a public two-plugin contract (`HarnessCorePlugin`
  headless, `DemoHarnessPlugin` windowed) with a non-exhaustive
  builder-constructed `HarnessConfig` and Bevy 0.19 message-based
  actions.
- Bevy is adopted with `default-features = false` and a curated
  feature list derived in a clean-container spike, because the default
  feature set would break all four CI workflows on missing system
  headers.
- The coverage ratchet gains a documented headless exclusion boundary,
  and release builds are scoped with `-p thysalion` plus a
  workflow-shape guard.

No implementation is included; the plan awaits approval per the
ExecPlan gate.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary

  • Converted the project into a six-crate Cargo workspace with shared dependency, metadata, and lint configuration.
  • Added the camera contract, two-plugin demo harness, headless-safe rig/input/diagnostics systems, windowed overlay, and screenshot capture.
  • Added the demo-empty Bevy application with scene, lighting, and material smoke tests.
  • Added behavioural, property-based, compile-fail, semantic, windowless, workflow, and Makefile validation tests.
  • Added demo launcher validation, screenshot slug sanitisation and sequencing, release-build scoping, and CI toolchain updates.
  • Updated developer/user documentation, repository layout, roadmap, and design records, including ADR-005 and the completed ExecPlan.

Automated checks pass. Manual GPU verification remains for interactive controls, overlay values, zoom bounds, and screenshot artefacts.

Walkthrough

The change converts the repository into a Cargo workspace, adds presentation and harness contracts, introduces the demo-empty Bevy binary, and updates build, release, CI, testing, documentation, and screenshot-handling workflows.

Changes

Workspace and build tooling

Layer / File(s) Summary
Workspace and workflow setup
Cargo.toml, crates/*/Cargo.toml, .github/workflows/*, Makefile, tests/*, .config/nextest.toml, .gitignore
Shared workspace metadata, dependencies, lints, workspace-aware commands, demo validation, release scoping, CI installer usage, and screenshot ignores are added or updated.
Camera and zoom contract
crates/presentation/src/*
Quadrant, ZoomBounds, validation, viewport sizing, and related property-based tests define the presentation camera API.
Headless harness core
crates/harness/src/{config,diagnostics,input,rig,lib}.rs, crates/harness/tests/*
The headless plugin installs configuration, diagnostics, synthetic input, message-driven rig updates, scheduling, and behavioural contract tests.
Windowed harness and demo
crates/harness/src/{camera,overlay,screenshot,windowed_tests}/*, crates/demos/*
Camera synchronization, overlay refresh, screenshot capture, demo packaging, scene setup, and windowed behaviour tests are added.
Architecture and contributor documentation
docs/*, src/lib.rs, crates/{knowledge,sim,world}/*
Workspace boundaries, plane responsibilities, demo conventions, roadmap status, execution planning, and composition-root documentation are recorded.

Sequence Diagram(s)

sequenceDiagram
  participant DemoEmpty
  participant DemoHarnessPlugin
  participant HarnessCore
  participant WindowedHarness
  participant ScreenshotSystem
  DemoEmpty->>DemoHarnessPlugin: create HarnessConfig and start app
  DemoHarnessPlugin->>HarnessCore: install core plugin and process actions
  DemoHarnessPlugin->>WindowedHarness: spawn camera and overlay
  WindowedHarness->>ScreenshotSystem: forward Screenshot actions
  ScreenshotSystem-->>DemoEmpty: save numbered screenshot
Loading

Possibly related PRs

Suggested labels: Roadmap

Poem

Workspace crates align in flight,
Cameras turn through corners bright.
Demos wake, screenshots gleam,
Headless tests guard every seam.
Build paths march in tidy streams.

🚥 Pre-merge checks | ✅ 19 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Observability ⚠️ Warning Only screenshot capture logs/error; new input, rig, overlay state transitions have no structured observability, so failures and degraded states remain opaque. Add structured logs or diagnostics at input, rig, overlay, and screenshot decision points (action, sequence, outcome); add bounded metrics/traces only where they aid diagnosis.
✅ Passed checks (19 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the PR’s main workspace and demo-harness scope and includes the roadmap reference.
Description check ✅ Passed The description clearly covers the workspace, harness, tests, docs, and demo changes in this changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Testing (Overall) ✅ Passed PASS: The new tests are broad and behavioural—real Bevy apps, BDD scenarios, proptests, trybuild, workflow/Makefile command checks, and sanitisation/scene assertions.
User-Facing Documentation ✅ Passed PASS: docs/users-guide.md adds a "Running the demos" section covering make demo, demo-empty, controls, screenshot naming, and the harness binding table.
Developer Documentation ✅ Passed Developer guide, ADR 005, design/repository docs, roadmap, and ExecPlan all reflect the new workspace/harness APIs and progress; no extra locales surfaced.
Module-Level Documentation ✅ Passed Scanned all 27 Rust source files; every module starts with //!, and the entry points explain purpose and relationships to sibling crates.
Testing (Unit And Behavioural) ✅ Passed Unit tests hit edge cases and invariants, while behavioural tests drive the real Bevy plugins, BDD scenarios, and make/workflow contracts at the correct boundaries.
Testing (Property / Proof) ✅ Passed PASS: The PR adds proptest model/contract tests for zoom bounds and rig transitions, plus an exhaustive Quadrant law test over Quadrant::ALL, matching the invariant-heavy changes.
Testing (Compile-Time / Ui) ✅ Passed A trybuild UI test pins the non-exhaustive compile-time contract, and overlay output is verified with focused semantic assertions rather than brittle snapshots.
Unit Architecture ✅ Passed PASS: queries stay pure, commands own mutation/side-effects, and ambient time/filesystem use is confined to the screenshot boundary with explicit tests.
Domain Architecture ✅ Passed PASS: The domain crates stay pure and dependency-light; presentation has no Bevy/filesystem imports, while Bevy, UI, and screenshot concerns live only in harness/demos.
Security And Privacy ✅ Passed No secrets, broad credentials, or unsafe sinks found; screenshot slugs are sanitised and workflow permissions stay minimal.
Performance And Resource Use ✅ Passed All new loops are bounded or user-driven; hot paths use fixed-size bindings and single-camera queries, with no unbounded collections or avoidable repeated I/O.
Concurrency And State ✅ Passed Shared state is owned by ECS resources, mutated only via message-driven systems with explicit Core→Windowed ordering; tests cover batched actions and toggle/sequence interleavings.
Architectural Complexity And Maintainability ✅ Passed PASS: The new plugins, config, and message types map to real seams; docs justify them, dependencies stay one-way, and tests pin the boundaries.
Rust Compiler Lint Integrity ✅ Passed No allow(dead_code|unused_*) or dead-code expectations were added; only narrow, justified lint expectations and three intentional clone() sites remain.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 1-1-establish-the-workspace-and-the-demo-harness-contract

Comment @coderabbitai help to get the list of available commands.

leynos added 4 commits July 24, 2026 19:05
Reverse the earlier deferral of `rstest-bdd` on user direction. The
headless behavioural test becomes a Gherkin specification
(`crates/harness/tests/features/harness.feature`, embedded in Stage B)
run through an in-repo Bevy harness adapter using the crate's
extensible harness support: `HarnessAdapter` with
`type Context = bevy::app::App`, steps borrowing the app via the
reserved `rstest_bdd_harness_context` fixture, per the third-party
harness adapter cookbook in the rstest-bdd users' guide.

Add the `rstest-bdd` 0.6.0-beta3 family to the approved dependency set
and `[workspace.dependencies]`, add a Stage A spike proving the adapter
compiles against Bevy 0.19, extend the developers' guide section to
document the behavioural-test convention, and record the change in a
second revision note. Unit-level mathematics remains plain rstest.
Convert the single-crate repository into a Cargo workspace with one
crate per architectural plane (`thysalion-world`, `thysalion-sim`,
`thysalion-knowledge`, `thysalion-presentation`) plus `thysalion-
harness` and `thysalion-demos`, and implement the shared demo harness
proven by the `demo-empty` binary.

- The root `thysalion` package stays as the composition root; the lint
  deny table moves to `[workspace.lints]` and every member inherits it.
- Bevy 0.19 is adopted with `default-features = false` and a curated
  feature list; the trim was verified in a clean container to need no
  system dev headers, and 0.19's umbrella features would otherwise drag
  in gamepad (libudev) and Wayland build dependencies.
- The presentation crate owns the pure camera contract of design §8.2
  (`Quadrant`, `ZoomBounds`); the harness consumes it, exposing the
  two-plugin contract (`HarnessCorePlugin` headless, `DemoHarnessPlugin`
  windowed) with a non-exhaustive builder-built `HarnessConfig`,
  message-based `HarnessAction`, and `DiagnosticsStore` paths including
  the `TICK_TIME` seam phase 4 writes through.
- Behavioural tests use rstest-bdd 0.6.0-beta3 through a Bevy harness
  adapter whose context is a `MinimalPlugins` app; when `InputPlugin`
  is absent the core plugin expires synthetic input at end of frame,
  fixing a genuine double-rotate defect the suite caught.
- Windowed-only modules and demo binaries sit outside the coverage
  ratchet via `cfg_attr(coverage_nightly, coverage(off))` and llvm-cov
  ignore patterns.
- `make` targets gain `--workspace`; the release workflow builds
  `-p thysalion` only (demo crates do not cross-compile for the six
  release targets), guarded by a new workflow-shape test; Whitaker is
  bumped to installer 0.2.7 whose lint suite matches the pinned
  nightly-2026-05-28 toolchain (older suites cannot compile Bevy 0.19).

Gates: `make check-fmt`, `make lint` (rustdoc, Clippy, Whitaker),
`make test` (38 tests), and `make spelling` all pass.
`cargo run --bin demo-empty` fails in a workspace with a root package:
Cargo only searches the root package's targets. Add `-p thysalion-demos`
to the `make demo` target and the binary's doc comment.

Verified by a 15-second windowed smoke run under WSLg: the window
"Thysalion — demo-empty" opens and the renderer initializes without
panics (software Vulkan on this GPU-less host).
Record the roadmap 1.1 delivery in the documentation set:

- Add ADR-005 covering the workspace crate layout: the root package as
  composition root, `crates/*` members, the dependency-sink rule, the
  curated Bevy feature list, the coverage boundary, and the release
  `-p thysalion` scoping.
- Rewrite repository-layout.md around the six-member workspace.
- Add a demo harness section to the developers' guide (two-plugin
  contract, `HarnessSet` ordering, headless testing recipe) and a
  running-the-demos section to the users' guide (key bindings,
  screenshots directory).
- Back-reference the crate layout from thysalion-design.md §6.1 and
  list the new documents in contents.md.
- Tick roadmap tasks 1.1.1 and 1.1.2 as complete.
- Close out the ExecPlan: progress, outcomes and retrospective,
  status COMPLETE. CodeRabbit reviewed the full branch with zero
  findings before this milestone.
@leynos
leynos marked this pull request as ready for review July 24, 2026 22:24

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @leynos, your pull request is larger than the review limit of 150000 diff characters

leynos added 2 commits July 24, 2026 23:25
Log the post-delivery evidence gathered after the docs milestone:

- Both pull-request CI runs green: 13 m 28 s on the code push and
  4 m 24 s warm cache on the docs push, well inside the 30-minute
  tolerance; the Whitaker 0.2.7 installer path worked in CI unmodified.
- CodeRabbit agent reviews of both milestones completed with zero
  findings.
- The maintainer verified quadrant rotation in the windowed demo;
  remaining manual checks (zoom bounds, F3 overlay, F12 screenshot)
  stay tracked as the open post-delivery item.
The maintainer captured screenshots/demo-empty-1784931927.png with F12
in the windowed demo. The capture confirms the isometric ground-plane
projection and shows the F3 overlay reporting live frame diagnostics
(14 fps under llvmpipe software rendering; "tick: n/a" is correct
because nothing measures into TICK_TIME until the simulation plane
exists). Zoom bounds remain the only open manual check.
chatgpt-codex-connector[bot]

This comment was marked as resolved.

@pandalump

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added the Roadmap label Jul 25, 2026
coderabbitai[bot]

This comment was marked as resolved.

Address ten of the eleven findings from CodeRabbit's first PR review
(one grammar suggestion declined in a reply — "an rstest-bdd" is
correct, as the letter r opens with a vowel sound):

- Clamp the initial zoom into the configured bounds in
  `RigState::from_config`, so a range excluding 1.0 starts in bounds.
- Add a process-local sequence counter to screenshot filenames
  (`<slug>-<seconds>-<sequence>.png`), so two captures within the same
  second cannot collide.
- Narrow the presentation crate's `float_arithmetic` expectation from
  module level to `Quadrant::yaw_radians`, `ZoomBounds::viewport_height`,
  and test-local sites; add a shared `assert_close` helper.
- Share an rstest `bounds` fixture across the zoom tests. The fixture
  returns `ZoomBounds::default()` (the same 0.5–4.0 range): Whitaker's
  `no_expect_outside_tests` rejects `.expect()` in a fixture fn, and a
  single-line fixture body trips `unused_braces` through the macro
  expansion, so the body stays multi-line and infallible.
- Harden the workflow-shape test: a `shared-actions` reference without
  `@<sha>` now fails instead of being skipped.
- Grammar and clarity fixes in the presentation crate docs, the
  developers' guide, thysalion-design §6.1, and the ExecPlan; the
  ExecPlan status line now names the open zoom-bounds manual check.
@buzzybee-df12

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

Address all seven findings from CodeRabbit's second PR review:

- Narrow the windowed camera module's `float_arithmetic` expectation
  from file level to the three functions that perform floating-point
  geometry (`sync_camera`, `camera_transform`, `shortest_angle_delta`);
  update ADR-005's allowance wording to match the function-scoped form.
- Spawn one screenshot capture per queued action instead of coalescing
  multiple requests into a single capture.
- Make the per-demo feature convention real: declare `demo-empty = []`,
  add `required-features` to the `[[bin]]`, and pass
  `--features demo-$(DEMO)` from the `make demo` target, so
  feature-gated demos stay runnable through the documented interface.
- Workspace-qualify the demo run commands in the ExecPlan and the
  binary's doc comment (`make demo`, or the full cargo invocation).
- Trim the ExecPlan retrospective's open-items list to the zoom-bounds
  check; the other items are recorded complete in Progress.
- Name `SCREENSHOT_KEY` alongside `KEY_BINDINGS` in the users' guide,
  and document the screenshot filename's new sequence component in both
  guides.
- Use "independently of" in ADR-005.

CodeRabbit withdrew its round-1 "an rstest-bdd" grammar finding after
the pronunciation-rule reply.
codescene-access[bot]

This comment was marked as outdated.

@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@buzzybee-df12

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

Address both findings from CodeRabbit's third PR review (all round-1
and round-2 threads were confirmed resolved):

- Add screenshot scheduling tests: consecutive capture paths are
  distinct within one second, hostile slugs stay confined to the
  screenshots directory, and a mixed action batch spawns one capture
  entity per screenshot action (behavioural test over a minimal app).
- Sanitize slugs to ASCII alphanumerics and hyphens when building
  capture paths, so a slug containing path separators cannot escape
  the screenshots directory.

Record in the ExecPlan that `make demo` input validation is delegated
to Cargo (an unknown DEMO fails with Cargo's own missing-feature
error), and that the zoom-bounds manual check is the only open item.
codescene-access[bot]

This comment was marked as outdated.

The demo-empty scene test checked only that the ground mesh asset
existed, so it would still pass if the plane were rebuilt at the wrong
dimensions. It now computes the mesh bounding box and asserts the
half-extents match `GROUND_SIZE / 2` in x and z, with a zero y extent
proving the ground stays flat.

Verified by mutation rather than by inspection: halving the plane's x
size fails the test with "the ground must span 24 world units in x and
z, got half-extents Vec3A(6.0, 0.0, 12.0)". The mutation was reverted
and the suite re-run green.
codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

CodeScene flagged the previous commit's `startup_spawns_one_lit_ground_
plane` as a Large Method: 72 lines against a 70-line threshold. Splitting
it four ways — entity counts, key-light contract, mesh extent, material
appearance — over shared `ground_handles` and `key_light` helpers keeps
every test under the threshold (largest is 26 lines) and makes a failure
name the property that broke rather than the whole scene.

No assertion was dropped or weakened.
codescene-access[bot]

This comment was marked as outdated.

@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@leynos

leynos commented Jul 26, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

Close the follow-up "Testing (Overall)" finding. Every existing plugin
test used the default configuration, so a regression that ignored a
demo's settings and fell back to `HarnessConfig::default()` would have
passed unnoticed.

`core_plugin_tests.rs` drives a non-default configuration (slug
`demo-custom`, zoom range 2.0-3.0, initial quadrant `SouthWest`) through
`HarnessCorePlugin::new(...)` rather than by inserting resources. The
range deliberately excludes the 1.0 baseline and shares no limit with the
0.5-4.0 default, so the initial clamp and both saturation points would
each expose a fallback. Zoom actions flow through the plugin's own
scheduled systems, in bounded loops.

`windowed_tests/custom_configuration.rs` does the same through
`DemoHarnessPlugin`: the camera spawns aimed at the configured quadrant,
and the fixed-vertical viewport height derives from the configured bounds
both at startup and after saturating zoom. It also asserts that the
expected height differs from the default-bounds height, so the test can
actually detect the fallback it is written to catch. Screenshot
configuration is covered through the installed slug rather than by
capturing, keeping the filesystem out of the test.

`demo_guard.rs` gains two positive launcher tests beside the existing
negative one; neither launches the windowed binary. They are
complementary because no single invocation shows everything:
`make --dry-run demo` prints the recipe before the shell runs it, proving
the `--features` and `--bin` arguments stay quoted but leaving the slug
as `demo-$DEMO_SLUG`; running with `CARGO` overridden to an echo stub
lets the shell expand everything, proving the default path resolves to
`demo-empty` and to no other slug, by which point the quotes are gone.

`windowed_tests` was split into `mod.rs` plus
`custom_configuration.rs` when the additions pushed it past the 400-line
module limit.
codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Jul 26, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

crates/harness/src/core_plugin_tests.rs

Comment on lines +127 to +138

fn zooming_in_clamps_at_the_configured_maximum(custom_config: HarnessConfig) {
    let mut app = core_app(custom_config);
    for _ in 0..ZOOM_STEPS_TO_SATURATE {
        send_and_update(&mut app, HarnessAction::ZoomIn);
    }
    let zoom = rig_zoom(&app);
    assert!(
        (zoom - CUSTOM_MAX_ZOOM).abs() < f32::EPSILON,
        "zoom must clamp at the configured maximum {CUSTOM_MAX_ZOOM}, got {zoom} (the default \
         maximum is 4.0)"
    );
}

❌ New issue: Code Duplication
The module contains 2 functions with similar structure: zooming_in_clamps_at_the_configured_maximum,zooming_out_clamps_at_the_configured_minimum

@coderabbitai

This comment was marked as resolved.

@buzzybee-df12

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Current state and relevant commits =='
git status --short
git log --oneline -15 -- \
  crates/harness/src/input.rs \
  crates/demos/src/bin/demo-empty.rs \
  crates/harness/tests \
  crates/harness/src \
  crates/demos

printf '%s\n' '== Structural outlines =='
ast-grep outline crates/harness/src/input.rs --items all
ast-grep outline crates/demos/src/bin/demo-empty.rs --items all

printf '%s\n' '== Input paths and adjacent tests =='
rg -n -C 8 \
  '(fn read_input|SCREENSHOT_KEY|AccumulatedMouseScroll|HarnessAction::(ZoomIn|ZoomOut|Screenshot)|just_released|#\[cfg\(test\)\]|#\[test\]|#\[rstest\])' \
  crates/harness/src/input.rs crates/harness/tests crates/harness/src

printf '%s\n' '== Demo scene setup and tests =='
rg -n -C 10 \
  '(fn (main|spawn_ground)|add_systems\(Startup|DirectionalLight|Mesh3d|MeshMaterial3d|StandardMaterial|illuminance|shadow_maps_enabled|#\[cfg\(test\)\]|#\[test\])' \
  crates/demos/src/bin/demo-empty.rs crates/demos

printf '%s\n' '== Focused full files =='
cat -n crates/harness/src/input.rs
cat -n crates/demos/src/bin/demo-empty.rs

printf '%s\n' '== ExecPlan validation references =='
rg -n -C 3 \
  '(scroll|F12|screenshot|demo-empty|spawn_ground|validation evidence|Validation)' \
  docs/execplans/1-1-establish-the-workspace-and-the-demo-harness-contract.md \
  || true

Length of output: 146664


@leynos: Mark Testing (Overall) resolved.

Current code at commit 563de61 directly covers every reported path:

  • read_input scroll behaviourcrates/harness/src/input.rs tests positive and negative vertical scroll, small positive scroll, zero scroll, horizontal-only scroll, and diagonal scroll. The tests run the actual read_input system in a headless Bevy app and assert the emitted HarnessAction values.
  • F12 release behaviourthe_screenshot_key_fires_once_on_release_and_never_on_press drives SCREENSHOT_KEY through press, update, release, update, and a further update. It asserts no action on press, exactly one Screenshot on release, and no repeat.
  • demo-empty startup scenecrates/demos/src/bin/demo-empty.rs runs spawn_ground in a headless app and asserts exactly one ground entity and directional light, the light’s 12_000.0 illuminance and enabled shadow maps, ground mesh geometry, and material albedo/roughness.

The ExecPlan also records validation evidence for these additions. No further implementation, AI-agent prompt, or follow-up issue is required for this finding.

CodeScene flagged `zooming_in_clamps_at_the_configured_maximum` and
`zooming_out_clamps_at_the_configured_minimum` as duplicates: both built
the same app, drove the same bounded loop, and asserted epsilon equality
against one configured bound. They are now a single
`zooming_clamps_at_the_configured_bound` with two `#[case]` entries
carrying the action, the expected bound, its label, and the default bound
for that direction.

Two lint interactions shaped the result:

- Four `#[case]` parameters plus an injected fixture would be five
  arguments, over the workspace `too_many_arguments` limit, so the
  configuration is built directly from the same fixture functions rather
  than injected.
- `rstest` moves a `#[case]`-parameterized body into generated case
  functions, where a function-level `#[expect]` no longer applies, so the
  epsilon comparison moved into an `assert_zoom_at` helper carrying the
  existing `float_arithmetic` rationale.

The diagnostic still names the configured bound, the observed value, and
the default it must be distinguished from; verified by temporarily
pointing a case at a wrong bound, which reports "zoom must clamp at the
configured maximum 2.75, got 3 (the default maximum is 4)".
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Current PR state and recent relevant commits =='
git status --short
git log --oneline -15 -- \
  crates/harness/src/core_plugin_tests.rs \
  crates/harness/src/windowed_tests.rs \
  crates/harness/src/screenshot.rs \
  crates/harness/tests \
  tests/demo_guard.rs \
  Makefile

printf '%s\n' '== Candidate test/module outlines =='
for file in \
  crates/harness/src/core_plugin_tests.rs \
  crates/harness/src/windowed_tests.rs \
  crates/harness/src/screenshot.rs \
  tests/demo_guard.rs
do
  if test -f "$file"; then
    printf '\n-- %s --\n' "$file"
    ast-grep outline "$file" --items all
  fi
done

printf '%s\n' '== Custom-config and launcher evidence =='
rg -n -C 8 \
  '(Harness(Core|Demo)Plugin::new|HarnessConfig::new|with_(window_title|zoom_bounds|initial_quadrant)|CUSTOM_(MIN|MAX)_ZOOM|custom_config|CaptureSequence|capture_path|make --dry-run demo|--features|--bin|DEMO_ALLOWED|DEMO_SLUG|DEMO must be one of)' \
  crates/harness tests Makefile \
  || true

printf '%s\n' '== Focused test source =='
for file in \
  crates/harness/src/core_plugin_tests.rs \
  crates/harness/src/windowed_tests.rs \
  crates/harness/src/screenshot.rs \
  crates/harness/tests/headless/support.rs \
  tests/demo_guard.rs \
  Makefile
do
  if test -f "$file"; then
    printf '\n== %s ==\n' "$file"
    cat -n "$file"
  fi
done

printf '%s\n' '== Existing open issues potentially covering remaining work =='
gh issue list --repo leynos/thysalion --state open --limit 100 \
  --json number,title,url,body \
  --jq '.[] | "#\(.number) \(.title)\n\(.url)\n\(.body)\n---"' \
  || true

Length of output: 95996


@leynos: Mark Testing (Overall) resolved against the current codegraph at commit 563de61.

  • HarnessCorePlugin: crates/harness/src/core_plugin_tests.rs drives a non-default HarnessConfig through HarnessCorePlugin::new(custom_config). It verifies the installed slug, bounds, and initial quadrant; verifies initial zoom clamping; and drives real HarnessAction messages through update cycles to prove clamping at the custom 2.0..=3.0 bounds rather than the defaults.

  • DemoHarnessPlugin: crates/harness/src/windowed_tests/custom_configuration.rs drives a non-default configuration through the full headless windowed-plugin setup. It verifies config-resource propagation, camera yaw for the configured initial quadrant, and orthographic fixed-vertical viewport heights derived from the custom zoom bounds after real zoom actions. The non-default slug is also verified in the plugin-installed configuration; crates/harness/src/screenshot.rs reads this same resource’s config.slug when constructing capture paths.

  • Supported launcher path: tests/demo_guard.rs now positively pins the default launcher without opening a window. make_dry_run_demo_renders_a_quoted_cargo_invocation checks the package-scoped, quoted invocation, while make_demo_resolves_the_default_launcher_to_demo_empty replaces CARGO with an echo stub and verifies that the guarded recipe resolves to demo-empty. The existing test still proves an unsupported demo fails before Cargo runs.

No further implementation work or follow-up GitHub issue is required for this check. Source inspection confirms the coverage exists; validate the command results in CI or a full development environment.

@coderabbitai

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

Rename the parameterized clamp test's case parameters and the helper's
signature to `expected_bound`, `bound_name`, and `default_bound`, so each
reads as the role it plays at the call site rather than as a bare
`expected`/`bound` pair. Behaviour and assertion output are unchanged.
@leynos
leynos merged commit 3f23feb into main Jul 26, 2026
5 checks passed
@leynos
leynos deleted the 1-1-establish-the-workspace-and-the-demo-harness-contract branch July 26, 2026 17:21
@leynos

leynos commented Jul 26, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai please create a new GitHub issue for the following:

Work on GitHub PR #7.

Resolve the remaining CodeScene code-duplication finding in:

  • File: crates/harness/src/core_plugin_tests.rs
  • Symbols: zooming_in_clamps_at_the_configured_maximum
    and zooming_out_clamps_at_the_configured_minimum

Verify the current code before editing. The two tests both build the real
HarnessCorePlugin app through core_app(custom_config), send
ZOOM_STEPS_TO_SATURATE messages through send_and_update, read RigState with
rig_zoom, and compare the result with a configured bound. Their only semantic
differences are the action, expected bound, bound label, and corresponding
default value.

Replace both tests with one parameterized #[rstest] named:

zooming_clamps_at_the_configured_bound

Add exactly these two cases:

  • HarnessAction::ZoomIn, CUSTOM_MAX_ZOOM, "maximum", 4.0
  • HarnessAction::ZoomOut, CUSTOM_MIN_ZOOM, "minimum", 0.5

Pass the case values as:

  • action: HarnessAction
  • expected_bound: f32
  • bound_name: &str
  • default_bound: f32

Keep the test’s existing behaviour:

  1. Construct the app only through core_app(custom_config).
  2. Retain the bounded ZOOM_STEPS_TO_SATURATE loop.
  3. Drive every action through send_and_update.
  4. Retain an item-scoped #[expect(clippy::float_arithmetic)] with the existing
    epsilon-comparison rationale.
  5. Preserve an assertion message that reports the configured bound, actual
    zoom, and corresponding default bound.

Do not alter production harness code, HarnessConfig values, scheduling,
message handling, or unrelated tests.

Run and report actual results for:

  1. cargo fmt --check
  2. cargo clippy --workspace --all-targets --all-features -- -D warnings
  3. cargo test --workspace --all-targets --all-features

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Target test module and named symbols =='
ast-grep outline crates/harness/src/core_plugin_tests.rs --items all
rg -n -C 16 \
  'fn zooming_(in_clamps_at_the_configured_maximum|out_clamps_at_the_configured_minimum)|ZOOM_STEPS_TO_SATURATE|send_and_update|rig_zoom|CUSTOM_(MIN|MAX)_ZOOM' \
  crates/harness/src/core_plugin_tests.rs

printf '%s\n' '== Existing open issues that could cover this follow-up =='
gh issue list \
  --repo leynos/thysalion \
  --state open \
  --limit 100 \
  --search 'CodeScene duplication HarnessCorePlugin zoom clamp' \
  --json number,title,url,body \
  --jq '.[] | "#\(.number) \(.title)\n\(.url)\n\(.body)\n---"' || true

Length of output: 8405


@leynos: Do not create a follow-up issue. The CodeScene duplication finding is already resolved in the current codegraph.

crates/harness/src/core_plugin_tests.rs now replaces the two named tests with zooming_clamps_at_the_configured_bound at Line 147. It preserves the required real-plugin execution path, bounded saturation loop, two #[case] variants, and narrow epsilon-comparison lint handling through assert_zoom_at.

No equivalent open issue exists, and opening one for already-completed work would create stale tracking.

@pandalump

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/demos/src/bin/demo-empty.rs (1)

93-108: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Remove the temporary Vec allocations from these singleton queries.

  • crates/demos/src/bin/demo-empty.rs#L93-L108: use query.single(app.world()).expect("startup must spawn exactly one ground entity"), then clone the handles.
  • crates/demos/src/bin/demo-empty.rs#L110-L124: use query.single(app.world()).expect("startup must spawn exactly one directional light"), then copy the light.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/demos/src/bin/demo-empty.rs` around lines 93 - 108, Replace the
temporary collection in ground_handles with a singleton query using
query.single(app.world()).expect("startup must spawn exactly one ground
entity"), then clone the mesh and material handles. Apply the same change in
crates/demos/src/bin/demo-empty.rs lines 110-124 for the directional-light
query: use single(...).expect("startup must spawn exactly one directional
light") and copy the light value.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/harness/src/windowed_tests/custom_configuration.rs`:
- Around line 28-39: Convert custom_bounds and custom_config into rstest
fixtures by adding the appropriate #[fixture] attributes, preserving their
existing values and construction logic. Update all three tests in this module to
receive the relevant fixture parameters through rstest injection instead of
calling the setup functions directly.

In `@tests/demo_guard.rs`:
- Around line 9-11: Update the module-level documentation comment in
tests/demo_guard.rs to insert “in” between “launcher” and “two complementary
ways,” preserving the surrounding wording.
- Around line 28-33: Update run_make to remove inherited GNUMAKEFLAGS, CARGO,
and DEMO variables before spawning make, while preserving explicit command-line
arguments and the existing MAKEFLAGS/MFLAGS isolation. Apply the same
environment isolation to the other run_make call sites covered by this comment.

---

Outside diff comments:
In `@crates/demos/src/bin/demo-empty.rs`:
- Around line 93-108: Replace the temporary collection in ground_handles with a
singleton query using query.single(app.world()).expect("startup must spawn
exactly one ground entity"), then clone the mesh and material handles. Apply the
same change in crates/demos/src/bin/demo-empty.rs lines 110-124 for the
directional-light query: use single(...).expect("startup must spawn exactly one
directional light") and copy the light value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e1fc3e86-df6e-4407-ab06-9b463e135021

📥 Commits

Reviewing files that changed from the base of the PR and between a094a54 and 83bdcfb.

📒 Files selected for processing (7)
  • crates/demos/src/bin/demo-empty.rs
  • crates/harness/src/core_plugin_tests.rs
  • crates/harness/src/lib.rs
  • crates/harness/src/windowed_tests/custom_configuration.rs
  • crates/harness/src/windowed_tests/mod.rs
  • docs/execplans/1-1-establish-the-workspace-and-the-demo-harness-contract.md
  • tests/demo_guard.rs

Comment on lines +28 to +39
fn custom_bounds() -> ZoomBounds {
match ZoomBounds::new(CUSTOM_MIN_ZOOM, CUSTOM_MAX_ZOOM) {
Ok(bounds) => bounds,
Err(error) => panic!("the custom zoom range must be valid: {error}"),
}
}

fn custom_config() -> HarnessConfig {
HarnessConfig::new(CUSTOM_SLUG)
.with_zoom_bounds(custom_bounds())
.with_initial_quadrant(CUSTOM_QUADRANT)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- target file ---\n'
cat -n crates/harness/src/windowed_tests/custom_configuration.rs

printf '\n--- nearby tests using custom_bounds/custom_config ---\n'
rg -n "custom_bounds|custom_config|ZoomBounds::new\\(|HarnessConfig::new\\(" crates/harness/src/windowed_tests -S

printf '\n--- file outline ---\n'
ast-grep outline crates/harness/src/windowed_tests/custom_configuration.rs --view expanded

Repository: leynos/thysalion

Length of output: 245


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- target file ---'
cat -n crates/harness/src/windowed_tests/custom_configuration.rs

printf '\n%s\n' '--- nearby tests using custom_bounds/custom_config ---'
rg -n "custom_bounds|custom_config|ZoomBounds::new\(|HarnessConfig::new\(" crates/harness/src/windowed_tests -S

printf '\n%s\n' '--- file outline ---'
ast-grep outline crates/harness/src/windowed_tests/custom_configuration.rs --view expanded

Repository: leynos/thysalion

Length of output: 7945


Convert the shared setup into rstest fixtures. Use #[fixture] for custom_bounds and custom_config, then inject them into the three tests so the shared configuration lives in one place.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/harness/src/windowed_tests/custom_configuration.rs` around lines 28 -
39, Convert custom_bounds and custom_config into rstest fixtures by adding the
appropriate #[fixture] attributes, preserving their existing values and
construction logic. Update all three tests in this module to receive the
relevant fixture parameters through rstest injection instead of calling the
setup functions directly.

Source: Path instructions

Comment thread tests/demo_guard.rs
Comment on lines +9 to +11
//! Neither positive test launches the windowed demo, which would open a
//! window and block. They inspect the launcher two complementary ways,
//! because no single invocation shows everything:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the missing preposition.

Change “They inspect the launcher two complementary ways” to “They inspect the launcher in two complementary ways”.

Triage: [type:grammar]

Proposed correction
-//! window and block. They inspect the launcher two complementary ways,
+//! window and block. They inspect the launcher in two complementary ways,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/demo_guard.rs` around lines 9 - 11, Update the module-level
documentation comment in tests/demo_guard.rs to insert “in” between “launcher”
and “two complementary ways,” preserving the surrounding wording.

Source: Path instructions

Comment thread tests/demo_guard.rs
Comment on lines +28 to +33
fn run_make(args: &[&str]) -> std::process::Output {
match Command::new("make")
.args(args)
.current_dir(env!("CARGO_MANIFEST_DIR"))
.env_remove("MAKEFLAGS")
.env_remove("MFLAGS")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the launcher tests hermetic.

run_make inherits DEMO and CARGO. An inherited CARGO can change the dry-run command, while an inherited DEMO can select another demo or make the “default” test fail before reaching the echo stub. Clear these child-process variables while retaining explicit command-line overrides.

Proposed isolation fix
         .env_remove("MAKEFLAGS")
         .env_remove("MFLAGS")
+        .env_remove("GNUMAKEFLAGS")
+        .env_remove("CARGO")
+        .env_remove("DEMO")
         .output()

Also applies to: 77-78, 103-107

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/demo_guard.rs` around lines 28 - 33, Update run_make to remove
inherited GNUMAKEFLAGS, CARGO, and DEMO variables before spawning make, while
preserving explicit command-line arguments and the existing MAKEFLAGS/MFLAGS
isolation. Apply the same environment isolation to the other run_make call sites
covered by this comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants