Skip to content

Use flock._reserveName for name allocation across creators and update tests#507

Merged
tracygardner merged 2 commits intomainfrom
codex/refactor-name-allocation-to-use-_reservename
Apr 5, 2026
Merged

Use flock._reserveName for name allocation across creators and update tests#507
tracygardner merged 2 commits intomainfrom
codex/refactor-name-allocation-to-use-_reservename

Conversation

@tracygardner
Copy link
Copy Markdown
Contributor

@tracygardner tracygardner commented Apr 5, 2026

Motivation

  • Replace scattered ad-hoc name uniqueness logic with a single reservation API to avoid race conditions and centralize naming behavior.
  • Ensure all mesh/effect/CSG creation paths consistently route name allocation through the same mechanism.
  • Add tests to verify callers use the reservation API so future changes remain correct.

Description

  • Replaced direct scene.getMeshByName checks and manual _ + getUniqueId() suffixing with calls to flock._reserveName(...) in multiple creators including createBox, createSphere, createCylinder, createCapsule, createPlane, create3DText, cloneMesh, createParticleEffect, and CSG identity resolution (resolveCsgModelIdentity).
  • Kept existing recycling and metadata handling while centralizing name reservation; callers now receive the reserved/unique name returned by flock._reserveName.
  • Added unit tests and instrumentation to assert that name allocation for shapes, clones, particle effects, merged meshes, objects, and character creation is routed through flock._reserveName.

Testing

  • Ran the test suite files modified: tests/shapes.test.js, tests/scene.test.js, tests/effects.test.js, tests/materials.test.js, tests/objects.test.js, and tests/characterAnimations.test.js with the new assertions for flock._reserveName usage.
  • All added and existing automated tests passed locally (including the new reservation checks).

Codex Task

Summary by CodeRabbit

  • Refactor

    • Unified name reservation across shape creation, particle effects, cloning, and object/character creation so repeated uses of the same base name produce distinct runtime IDs, reducing visible naming collisions.
  • Tests

    • Added extensive tests validating that repeated creations with identical base names return unique IDs across shapes, effects, clones, objects, and characters.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Apr 5, 2026

Deploying flockdev with  Cloudflare Pages  Cloudflare Pages

Latest commit: dd902f9
Status: ✅  Deploy successful!
Preview URL: https://ad91c6c7.flockdev.pages.dev
Branch Preview URL: https://codex-refactor-name-allocati.flockdev.pages.dev

View logs

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

📝 Walkthrough

Walkthrough

Consolidates name/ID allocation by replacing ad-hoc collision checks and unique-suffixing with unconditional flock._reserveName() calls across CSG, effects, scene cloning, and shape factories; adds tests to verify repeated use of the same base name yields distinct reserved IDs.

Changes

Cohort / File(s) Summary
API: name reservation
api/csg.js, api/effects.js, api/scene.js, api/shapes.js
Replaced conditional mesh-existence checks and getUniqueId() suffixing with unconditional flock._reserveName(<id>) to obtain final reserved names for models, particle systems, clones, and shapes. Downstream logic unchanged.
Tests: reservation behavior
tests/characterAnimations.test.js, tests/effects.test.js, tests/materials.test.js, tests/objects.test.js, tests/scene.test.js, tests/shapes.test.js
Added tests that create duplicate-named resources (characters, effects, merges, objects, clones, shapes/3D text) and assert returned IDs differ, ensuring reservation prevents collisions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hop through names both near and far,
I nibble conflicts, reserve each star,
No more ad‑hoc suffix, no duplicate fright,
reserveName hums through day and night,
Hooray — each mesh gets its own bright light! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: centralizing name allocation by using flock._reserveName across multiple creator functions and updating tests to verify this behavior.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 codex/refactor-name-allocation-to-use-_reservename

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
tests/shapes.test.js (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Fix Prettier formatting issue.

The CI pipeline reports a Prettier formatting violation in this file. Run npx prettier --write tests/shapes.test.js to resolve.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/shapes.test.js` at line 1, Prettier flagged formatting in
tests/shapes.test.js; run the formatter (e.g., npx prettier --write
tests/shapes.test.js) or apply Prettier rules to reformat the file so the import
statement (import { expect } from "chai";) and the rest of tests/shapes.test.js
conform to the project's Prettier configuration, then re-stage the reformatted
file and push the commit.
🧹 Nitpick comments (1)
api/scene.js (1)

642-689: Consider releasing reserved name on failure paths.

If sourceMesh is null/disposed (line 643 returns early), or if clone is falsy (line 651), the reserved name remains in _nameRegistry but is never used. Per the _releaseName helper in flock.js, reservations should be released on failure.

This is an optional improvement that could be addressed in a follow-up.

💡 Suggested enhancement for failure paths
     flock.whenModelReady(sourceMeshName, (sourceMesh) => {
-      if (!sourceMesh || sourceMesh.isDisposed?.()) return;
+      if (!sourceMesh || sourceMesh.isDisposed?.()) {
+        flock._releaseName(uniqueCloneId);
+        return;
+      }

       flock._recycleOldestByKey(sourceMeshName);

       const clone = sourceMesh.clone(uniqueCloneId);

+      if (!clone) {
+        flock._releaseName(uniqueCloneId);
+        return;
+      }
+
       flock._registerInstance(sourceMeshName, clone.name);

-      if (clone) {
         sourceMesh.computeWorldMatrix(true);
         // ... rest of the code
-      }
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/scene.js` around lines 642 - 689, The reserved clone name registered via
flock._registerInstance(uniqueCloneId) can be leaked when sourceMesh is
null/disposed or when clone is falsy; update the flock.whenModelReady callback
to call the name-release helper (flock._releaseName or the corresponding release
API) before any early return: call it immediately when sourceMesh is
null/disposed and also when clone is falsy after registering (then return),
ensuring the reservation is freed in both failure paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/effects.test.js`:
- Around line 82-132: The test wraps flock._reserveName but calls createBox
while the wrapper is active which may append extra names to reserveCalls; move
the call to flock.createBox("effectReserveEmitter", ...) to before you replace
flock._reserveName (i.e., create the emitterMesh first), then install the
wrapper and call flock.createParticleEffect twice to populate reserveCalls;
additionally ensure you restore flock._reserveName (using originalReserveName)
before invoking done/done(error) by restoring inside the try/catch (or a finally
that restores and then calls done) so the original _reserveName is reinstated
prior to ending the test; refer to flock._reserveName, originalReserveName,
reserveCalls, createBox, createParticleEffect, createdMeshes and createdEffects
when making these edits.

In `@tests/scene.test.js`:
- Around line 394-428: The test wraps flock._reserveName to record calls but
installs that wrapper before calling createBox, and createBox itself calls
flock._reserveName, so reserveCalls includes the box name; fix by creating the
box first (call flock.createBox(...) and push boxId into createdIds), then
install the wrapper around flock._reserveName to capture reserveClone calls,
then perform the two flock.cloneMesh(...) calls; keep restoring
flock._reserveName in the finally block and leave assertions
(expect(reserveCalls)... and expect(firstCloneId)... ) unchanged.

---

Outside diff comments:
In `@tests/shapes.test.js`:
- Line 1: Prettier flagged formatting in tests/shapes.test.js; run the formatter
(e.g., npx prettier --write tests/shapes.test.js) or apply Prettier rules to
reformat the file so the import statement (import { expect } from "chai";) and
the rest of tests/shapes.test.js conform to the project's Prettier
configuration, then re-stage the reformatted file and push the commit.

---

Nitpick comments:
In `@api/scene.js`:
- Around line 642-689: The reserved clone name registered via
flock._registerInstance(uniqueCloneId) can be leaked when sourceMesh is
null/disposed or when clone is falsy; update the flock.whenModelReady callback
to call the name-release helper (flock._releaseName or the corresponding release
API) before any early return: call it immediately when sourceMesh is
null/disposed and also when clone is falsy after registering (then return),
ensuring the reservation is freed in both failure paths.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 18956415-872e-4749-9a6d-764a9346128b

📥 Commits

Reviewing files that changed from the base of the PR and between dfddca8 and b1c07f9.

📒 Files selected for processing (10)
  • api/csg.js
  • api/effects.js
  • api/scene.js
  • api/shapes.js
  • tests/characterAnimations.test.js
  • tests/effects.test.js
  • tests/materials.test.js
  • tests/objects.test.js
  • tests/scene.test.js
  • tests/shapes.test.js

Comment on lines +82 to +132
it("should route particle effect name allocation through _reserveName", function (done) {
this.timeout(5000);
const originalReserveName = flock._reserveName;
const reserveCalls = [];

flock._reserveName = (name) => {
reserveCalls.push(name);
return originalReserveName.call(flock, name);
};

const emitterId = flock.createBox("effectReserveEmitter", {
color: "#FF0000",
width: 1,
height: 1,
depth: 1,
position: [0, 0, 0],
});
createdMeshes.push(emitterId);

const firstEffectName = flock.createParticleEffect("reserveEffect", {
emitterMesh: emitterId,
emitRate: 10,
colors: { start: "#ffffff", end: "#ffffff" },
alphas: { start: 1, end: 0 },
sizes: { start: 1, end: 1 },
lifetime: { min: 0.1, max: 0.2 },
shape: "flare.png",
});
const secondEffectName = flock.createParticleEffect("reserveEffect", {
emitterMesh: emitterId,
emitRate: 10,
colors: { start: "#ffffff", end: "#ffffff" },
alphas: { start: 1, end: 0 },
sizes: { start: 1, end: 1 },
lifetime: { min: 0.1, max: 0.2 },
shape: "flare.png",
});
createdEffects.push(firstEffectName, secondEffectName);

setTimeout(() => {
try {
expect(reserveCalls).to.deep.equal(["reserveEffect", "reserveEffect"]);
expect(firstEffectName).to.not.equal(secondEffectName);
done();
} catch (error) {
done(error);
} finally {
flock._reserveName = originalReserveName;
}
}, 100);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Two issues with this test: assertion fragility and finally placement.

  1. Same fragility issue: createBox on line 92 is called while the wrapper is active. If createBox also routes through _reserveName (per the PR summary), the assertion on line 123 will fail.

  2. finally runs after done(): The current structure calls done() or done(error) before the finally block restores _reserveName. While this works, if any subsequent test runs before the finally block completes (unlikely but possible), it could see the wrapped version.

🔧 Proposed fix
     it("should route particle effect name allocation through _reserveName", function (done) {
       this.timeout(5000);
       const originalReserveName = flock._reserveName;
       const reserveCalls = [];

       flock._reserveName = (name) => {
         reserveCalls.push(name);
         return originalReserveName.call(flock, name);
       };

+      try {
       const emitterId = flock.createBox("effectReserveEmitter", {
         color: "#FF0000",
         width: 1,
         height: 1,
         depth: 1,
         position: [0, 0, 0],
       });
       createdMeshes.push(emitterId);
+      } finally {
+        // Restore before effect creation to isolate the test
+      }
+
+      // Re-wrap for effect creation only
+      flock._reserveName = (name) => {
+        reserveCalls.push(name);
+        return originalReserveName.call(flock, name);
+      };

       const firstEffectName = flock.createParticleEffect("reserveEffect", {
         // ...
       });
       // ...

       setTimeout(() => {
         try {
-          expect(reserveCalls).to.deep.equal(["reserveEffect", "reserveEffect"]);
+          expect(reserveCalls.filter(n => n === "reserveEffect")).to.have.lengthOf(2);
           expect(firstEffectName).to.not.equal(secondEffectName);
+          flock._reserveName = originalReserveName;
           done();
         } catch (error) {
+          flock._reserveName = originalReserveName;
           done(error);
-        } finally {
-          flock._reserveName = originalReserveName;
         }
       }, 100);
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/effects.test.js` around lines 82 - 132, The test wraps
flock._reserveName but calls createBox while the wrapper is active which may
append extra names to reserveCalls; move the call to
flock.createBox("effectReserveEmitter", ...) to before you replace
flock._reserveName (i.e., create the emitterMesh first), then install the
wrapper and call flock.createParticleEffect twice to populate reserveCalls;
additionally ensure you restore flock._reserveName (using originalReserveName)
before invoking done/done(error) by restoring inside the try/catch (or a finally
that restores and then calls done) so the original _reserveName is reinstated
prior to ending the test; refer to flock._reserveName, originalReserveName,
reserveCalls, createBox, createParticleEffect, createdMeshes and createdEffects
when making these edits.

Comment on lines +394 to +428
it("should route clone name allocation through _reserveName", function () {
const originalReserveName = flock._reserveName;
const reserveCalls = [];

flock._reserveName = (name) => {
reserveCalls.push(name);
return originalReserveName.call(flock, name);
};

try {
const boxId = flock.createBox("cloneReserveSrc", {
color: "#996633",
width: 1,
height: 1,
depth: 1,
position: [0, 0, 0],
});
createdIds.push(boxId);

const firstCloneId = flock.cloneMesh({
sourceMeshName: boxId,
cloneId: "reserveClone",
});
const secondCloneId = flock.cloneMesh({
sourceMeshName: boxId,
cloneId: "reserveClone",
});
createdIds.push(firstCloneId, secondCloneId);

expect(reserveCalls).to.deep.equal(["reserveClone", "reserveClone"]);
expect(firstCloneId).to.not.equal(secondCloneId);
} finally {
flock._reserveName = originalReserveName;
}
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if createBox in api/shapes.js calls _reserveName
# Expected: If createBox calls _reserveName, this test's assertion would be incorrect

rg -n '_reserveName' api/shapes.js | head -20

Repository: flipcomputing/flock

Length of output: 350


Test assertion will fail—createBox also calls _reserveName.

The shell verification confirms that createBox in api/shapes.js (line 276) calls flock._reserveName. Since the wrapper is installed before createBox("cloneReserveSrc", ...) is called, the reserveCalls array will contain ["cloneReserveSrc", "reserveClone", "reserveClone"], not ["reserveClone", "reserveClone"] as asserted on line 423, causing the test to fail.

Move box creation before the wrapper installation:

Fix: Install wrapper after box creation
+      const boxId = flock.createBox("cloneReserveSrc", {
+        color: "#996633",
+        width: 1,
+        height: 1,
+        depth: 1,
+        position: [0, 0, 0],
+      });
+      createdIds.push(boxId);
+
       const originalReserveName = flock._reserveName;
       const reserveCalls = [];

       flock._reserveName = (name) => {
         reserveCalls.push(name);
         return originalReserveName.call(flock, name);
       };

       try {
-        const boxId = flock.createBox("cloneReserveSrc", {
-          color: "#996633",
-          width: 1,
-          height: 1,
-          depth: 1,
-          position: [0, 0, 0],
-        });
-        createdIds.push(boxId);
-
         const firstCloneId = flock.cloneMesh({
           sourceMeshName: boxId,
           cloneId: "reserveClone",
         });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/scene.test.js` around lines 394 - 428, The test wraps
flock._reserveName to record calls but installs that wrapper before calling
createBox, and createBox itself calls flock._reserveName, so reserveCalls
includes the box name; fix by creating the box first (call flock.createBox(...)
and push boxId into createdIds), then install the wrapper around
flock._reserveName to capture reserveClone calls, then perform the two
flock.cloneMesh(...) calls; keep restoring flock._reserveName in the finally
block and leave assertions (expect(reserveCalls)... and expect(firstCloneId)...
) unchanged.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/materials.test.js`:
- Line 946: Run Prettier over the failing test file to fix formatting: execute
prettier --write on tests/materials.test.js, stage and commit the updated file,
and push the change so the CI Prettier check passes; ensure you use the
repository’s Prettier config (prettier.config.js/.prettierrc) so the formatting
matches project rules.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 780d00d4-6cfe-4004-bedd-5dec19f2c82d

📥 Commits

Reviewing files that changed from the base of the PR and between b1c07f9 and dd902f9.

📒 Files selected for processing (6)
  • tests/characterAnimations.test.js
  • tests/effects.test.js
  • tests/materials.test.js
  • tests/objects.test.js
  • tests/scene.test.js
  • tests/shapes.test.js
✅ Files skipped from review due to trivial changes (4)
  • tests/objects.test.js
  • tests/scene.test.js
  • tests/effects.test.js
  • tests/characterAnimations.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/shapes.test.js

const mergedMesh = flock.scene.getMeshByName(id);
expect(mergedMesh.getTotalVertices()).to.be.greaterThan(0);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Address the Prettier formatting warning.

The pipeline reports a Prettier formatting check warning. Please run prettier --write on this file to resolve the formatting issue before merging.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/materials.test.js` at line 946, Run Prettier over the failing test file
to fix formatting: execute prettier --write on tests/materials.test.js, stage
and commit the updated file, and push the change so the CI Prettier check
passes; ensure you use the repository’s Prettier config
(prettier.config.js/.prettierrc) so the formatting matches project rules.

@tracygardner tracygardner merged commit 994d440 into main Apr 5, 2026
9 checks passed
@tracygardner tracygardner deleted the codex/refactor-name-allocation-to-use-_reservename branch April 5, 2026 14:58
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.

1 participant