Skip to content

Commit 882fa88

Browse files
authored
Merge pull request #9362 from decentraland/release/2026-07-13
release: 2026-07-13
2 parents eaa782e + 889485f commit 882fa88

299 files changed

Lines changed: 8525 additions & 1858 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,12 +344,12 @@ jobs:
344344
echo "baseline=$baseline" >> "$GITHUB_OUTPUT"
345345
echo "Baseline warnings: ${baseline:-<none>}"
346346
347-
# Hard gate: a PR may only merge if it strictly reduces the warning count.
348-
# Exception: release/hotfix PRs may merge when the count is unchanged (equality passes).
347+
# Hard gate: a dev-targeted PR may only merge if it strictly reduces the warning count.
348+
# Release/hotfix PRs skip this gate — each commit already passed it when merging into dev.
349349
# No baseline yet -> pass (the first dev push seeds it). Add the 'no-warning-ratchet'
350-
# label to bypass on a PR that legitimately cannot touch warnings.
350+
# label to bypass on a dev PR that legitimately cannot touch warnings.
351351
- name: Enforce warning reduction (PR)
352-
if: github.event_name == 'pull_request'
352+
if: github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'dev'
353353
env:
354354
COUNT: ${{ steps.warnings.outputs.count }}
355355
BASELINE: ${{ steps.baseline.outputs.baseline }}

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ Reviewers have repeatedly identified AI-generated code by these smells. Check yo
123123
* **Interfaces with one implementation and no test coverage.** Delete the interface. The concrete class is the contract.
124124
* **Per-frame logic inside a presenter/controller.** If you're writing `Tick(float dt)` or polling in a UI class, the work belongs in an `ECS` system (`BaseUnityLoopSystem` or `ControllerECSBridgeSystem`). Camera, time, player, and input are already ECS singletons — reach for `TryGet` in a system, not `Camera.main` in a presenter. Profiler markers come free in systems.
125125
* **Defensive null-checks against non-null declarations.** If the declared type is `T` (not `T?`), don't null-check it. Trust the annotations. Every redundant check is a lie to the reader about what can happen.
126+
* **`null!` on DTO fields for schema-required properties.** When a DTO class deserializes a JSON response from an API whose OpenAPI/schema definition marks the field as `required`, initializing with `= null!` is the correct pattern — it signals "non-null at runtime because the server guarantees it, but C# needs an initializer." The DTO class *must* include a schema-link comment (e.g. `// Server schema: social-service-ea docs/schemas.yaml#/…/SchemaName`) so reviewers can verify the contract. Fields that are *optional* in the schema must be declared nullable (`T?`) with no `null!`. This exception applies only to deserialized DTO fields — local variables, method return types, and non-DTO code must never use `null!`; use `T?` and propagate the nullable contract instead.
126127
* **Debug/mock code in production hot paths.** Runtime bools like `DebugRandomizeX` execute on every call in retail builds. Guard debug branches with `#if UNITY_EDITOR` or move them to an editor-only companion system — never rely on a runtime flag alone.
127128
* **Plugins initializing or mutating containers.** Containers are constructed top-down from the composition root. Plugins **read** from containers. A plugin that writes into a container is a signal the dependency graph is inverted — create a scoped container instead.
128129
* **`ObjectProxy` is an anti-pattern** — never introduce a new instance. The codebase has been swept of it; the only legitimate remaining uses model true runtime lifecycles (`StaticContainer.MainPlayerAvatarBaseProxy` — avatar set/released as the player loads, and `ExposedCameraData.CameraEntityProxy` — entity created during world build). Every other use was a wiring-order mistake and was eliminated by restructuring. To decouple without it, pick the matching recipe from `docs/architecture-overview.md` § "Deferred dependencies — decoupling without ObjectProxy": create the service before its consumers (hoist it out of a UI container into its own container), model an optional feature as a nullable dependency or null-object, let the container that owns a late-created service also construct the plugins that need it (`DynamicWorldContainer.WorldPlugins`), or pass per-scene data through `ECSWorldInstanceSharedDependencies`.

Explorer/Assets/DCL/ApplicationsGuards/ApplicationMinimumSpecsGuard/Tests/FakeSystemInfoProvider.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace DCL.ApplicationMinimumSpecsGuard.Tests
1+
using DCL.ApplicationMinimumSpecsGuard;
2+
3+
namespace DCL.ApplicationsGuards.ApplicationMinimumSpecsGuard.Tests
24
{
35
/// <summary>
46
/// A fake implementation of ISystemInfoProvider for testing purposes.
@@ -12,4 +14,4 @@ public class FakeSystemInfoProvider : ISystemInfoProvider
1214
public int GraphicsMemorySize { get; set; } = 8192;
1315
public int SystemMemorySize { get; set; } = 16384;
1416
}
15-
}
17+
}

Explorer/Assets/DCL/ApplicationsGuards/ApplicationMinimumSpecsGuard/Tests/SystemSpecUtilsShould.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
using DCL.ApplicationMinimumSpecsGuard;
12
using DCL.FeatureFlags;
23
using NUnit.Framework;
34
using System.Collections.Generic;
45

5-
namespace DCL.ApplicationMinimumSpecsGuard.Tests
6+
namespace DCL.ApplicationsGuards.ApplicationMinimumSpecsGuard.Tests
67
{
78
public class SystemSpecUtilsShould
89
{

Explorer/Assets/DCL/AvatarRendering/AvatarShape/Tests/EditMode/AvatarHideShould.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using DCL.AvatarRendering.AvatarShape.Tests.EditMode;
21
using DCL.AvatarRendering.Loading.Components;
32
using DCL.AvatarRendering.Wearables.Components;
43
using DCL.AvatarRendering.Wearables.Helpers;
@@ -7,7 +6,7 @@
76
using System.Collections.Generic;
87
using UnityEngine;
98

10-
namespace DCL.Tests
9+
namespace DCL.AvatarRendering.AvatarShape.Tests
1110
{
1211
public class AvatarHideShould
1312
{

Explorer/Assets/DCL/AvatarRendering/AvatarShape/Tests/EditMode/AvatarHighlightSystemShould.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using DCL.AvatarRendering.AvatarShape.Components;
33
using DCL.Interaction.Raycast.Components;
44
using ECS.TestSuite;
5-
using NSubstitute;
65
using NUnit.Framework;
76
using UnityEngine;
87

Explorer/Assets/DCL/AvatarRendering/AvatarShape/Tests/EditMode/AvatarTransformMatrixJobWrapperShould.cs

Lines changed: 64 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,85 +3,88 @@
33
using NUnit.Framework;
44
using UnityEngine;
55

6-
[Ignore("This produces 200mb worth of logs - @Nick revert this after your change")]
7-
public class AvatarTransformMatrixJobWrapperShould
6+
namespace DCL.AvatarRendering.AvatarShape.Tests
87
{
9-
private AvatarTransformMatrixJobWrapper jobWrapper;
10-
11-
[SetUp]
12-
public void SetUp()
13-
{
14-
jobWrapper = new AvatarTransformMatrixJobWrapper();
15-
}
16-
17-
[TearDown]
18-
public void TearDown()
8+
[Ignore("This produces 200mb worth of logs - @Nick revert this after your change")]
9+
public class AvatarTransformMatrixJobWrapperShould
1910
{
20-
jobWrapper.Dispose();
21-
}
22-
23-
[Test]
24-
public void AddNewAvatarIncrementsAvatarIndex()
25-
{
26-
var avatarBase = new GameObject().AddComponent<AvatarBase>();
27-
var transformMatrixComponent = AvatarTransformMatrixComponent.NewDefault();
28-
transformMatrixComponent.IndexInGlobalJobArray.TryGetValue(out int initialIndex);
11+
private AvatarTransformMatrixJobWrapper jobWrapper;
2912

30-
jobWrapper.RegisterAvatar(avatarBase, ref transformMatrixComponent);
13+
[SetUp]
14+
public void SetUp()
15+
{
16+
jobWrapper = new AvatarTransformMatrixJobWrapper();
17+
}
3118

32-
transformMatrixComponent.IndexInGlobalJobArray.TryGetValue(out int afterIndex);
33-
Assert.AreNotEqual(initialIndex, afterIndex);
34-
}
19+
[TearDown]
20+
public void TearDown()
21+
{
22+
jobWrapper.Dispose();
23+
}
3524

36-
[Test]
37-
public void ResizeArraysDoublesCapacity()
38-
{
39-
// Add avatars until we exceed the initial capacity and force a resize
40-
for (int i = 0; i < AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE + 1; i++)
25+
[Test]
26+
public void AddNewAvatarIncrementsAvatarIndex()
4127
{
4228
var avatarBase = new GameObject().AddComponent<AvatarBase>();
4329
var transformMatrixComponent = AvatarTransformMatrixComponent.NewDefault();
30+
transformMatrixComponent.IndexInGlobalJobArray.TryGetValue(out int initialIndex);
31+
4432
jobWrapper.RegisterAvatar(avatarBase, ref transformMatrixComponent);
33+
34+
transformMatrixComponent.IndexInGlobalJobArray.TryGetValue(out int afterIndex);
35+
Assert.AreNotEqual(initialIndex, afterIndex);
4536
}
4637

47-
// After resizing, the internal array size should be doubled
48-
Assert.AreEqual(AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE * 2, jobWrapper.CurrentAvatarAmountSupported);
49-
}
38+
[Test]
39+
public void ResizeArraysDoublesCapacity()
40+
{
41+
// Add avatars until we exceed the initial capacity and force a resize
42+
for (int i = 0; i < AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE + 1; i++)
43+
{
44+
var avatarBase = new GameObject().AddComponent<AvatarBase>();
45+
var transformMatrixComponent = AvatarTransformMatrixComponent.NewDefault();
46+
jobWrapper.RegisterAvatar(avatarBase, ref transformMatrixComponent);
47+
}
5048

51-
[Test]
52-
public void ReleasedIndexesAreReused()
53-
{
54-
var avatarBase = new GameObject().AddComponent<AvatarBase>();
55-
var transformMatrixComponent1 = AvatarTransformMatrixComponent.NewDefault();
56-
var transformMatrixComponent2 = AvatarTransformMatrixComponent.NewDefault();
49+
// After resizing, the internal array size should be doubled
50+
Assert.AreEqual(AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE * 2, jobWrapper.CurrentAvatarAmountSupported);
51+
}
5752

58-
// Add the first avatar
59-
jobWrapper.RegisterAvatar(avatarBase, ref transformMatrixComponent1);
60-
transformMatrixComponent1.IndexInGlobalJobArray.TryGetValue(out int firstIndex);
53+
[Test]
54+
public void ReleasedIndexesAreReused()
55+
{
56+
var avatarBase = new GameObject().AddComponent<AvatarBase>();
57+
var transformMatrixComponent1 = AvatarTransformMatrixComponent.NewDefault();
58+
var transformMatrixComponent2 = AvatarTransformMatrixComponent.NewDefault();
6159

62-
// Release the first avatar
63-
jobWrapper.ReleaseAvatar(ref transformMatrixComponent1);
60+
// Add the first avatar
61+
jobWrapper.RegisterAvatar(avatarBase, ref transformMatrixComponent1);
62+
transformMatrixComponent1.IndexInGlobalJobArray.TryGetValue(out int firstIndex);
6463

65-
// Add a second avatar and check if it reuses the released index
66-
jobWrapper.RegisterAvatar(avatarBase, ref transformMatrixComponent2);
67-
transformMatrixComponent2.IndexInGlobalJobArray.TryGetValue(out int secondIndex);
64+
// Release the first avatar
65+
jobWrapper.ReleaseAvatar(ref transformMatrixComponent1);
6866

69-
Assert.AreEqual(firstIndex, secondIndex);
70-
}
67+
// Add a second avatar and check if it reuses the released index
68+
jobWrapper.RegisterAvatar(avatarBase, ref transformMatrixComponent2);
69+
transformMatrixComponent2.IndexInGlobalJobArray.TryGetValue(out int secondIndex);
7170

72-
[Test]
73-
public void MatrixAndBoolArraysResize()
74-
{
75-
// Fill the wrapper to trigger a resize
76-
for (int i = 0; i < AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE + 1; i++)
77-
{
78-
var avatarBase = new GameObject().AddComponent<AvatarBase>();
79-
var transformMatrixComponent = AvatarTransformMatrixComponent.NewDefault();
80-
jobWrapper.RegisterAvatar(avatarBase, ref transformMatrixComponent);
71+
Assert.AreEqual(firstIndex, secondIndex);
8172
}
8273

83-
// The matrices and bools should have been resized to double their initial size
84-
Assert.AreEqual(AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE * 2, jobWrapper.MatrixFromAllAvatarsLength);
85-
Assert.AreEqual(AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE * 2, jobWrapper.UpdateAvatarLength);
74+
[Test]
75+
public void MatrixAndBoolArraysResize()
76+
{
77+
// Fill the wrapper to trigger a resize
78+
for (int i = 0; i < AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE + 1; i++)
79+
{
80+
var avatarBase = new GameObject().AddComponent<AvatarBase>();
81+
var transformMatrixComponent = AvatarTransformMatrixComponent.NewDefault();
82+
jobWrapper.RegisterAvatar(avatarBase, ref transformMatrixComponent);
83+
}
84+
85+
// The matrices and bools should have been resized to double their initial size
86+
Assert.AreEqual(AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE * 2, jobWrapper.MatrixFromAllAvatarsLength);
87+
Assert.AreEqual(AvatarTransformMatrixJobWrapper.AVATAR_ARRAY_SIZE * 2, jobWrapper.UpdateAvatarLength);
88+
}
8689
}
8790
}

Explorer/Assets/DCL/AvatarRendering/AvatarShape/Tests/EditMode/FakeWearable.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
using SceneRunner.Scene;
88
using System;
99
using System.Collections.Generic;
10-
using UnityEngine;
1110

12-
namespace DCL.AvatarRendering.AvatarShape.Tests.EditMode
11+
namespace DCL.AvatarRendering.AvatarShape.Tests
1312
{
1413
public class FakeWearable : IWearable
1514
{

Explorer/Assets/DCL/AvatarRendering/AvatarShape/Tests/EditMode/TextureArrayShouldBase.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
using System.Collections.Generic;
2-
using System.Net.Mime;
31
using DCL.AvatarRendering.AvatarShape.Rendering.TextureArray;
42
using NUnit.Framework;
3+
using System.Collections.Generic;
54
using UnityEngine;
65

76
namespace DCL.AvatarRendering.AvatarShape.Tests

Explorer/Assets/DCL/AvatarRendering/AvatarShape/Tests/EditMode/ToonTextureArrayShould.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using DCL.AvatarRendering.AvatarShape.Rendering.TextureArray;
21
using NUnit.Framework;
32

43
namespace DCL.AvatarRendering.AvatarShape.Tests

0 commit comments

Comments
 (0)