Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions extensions/renderers/unity/boxes/crypt_kit_v1_boxes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"version": 1,
"ortho": 11.7851,
"cols": 16, "rows": 12,
"provenance": "kit-derived (build_room_kit ExportBoxes): per-mass renderer bounds of KitRoom_crypt",
"boxes": [
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-15, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-13, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-11, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-9, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-7, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-5, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-3, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [1, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [3, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [5, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [7, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [9, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [11, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [13, 0, 11]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [15, 0, 11]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-13, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-11, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-9, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-7, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-5, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-3, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-1, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [1, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [3, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [5, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [7, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [9, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [11, 0, -11]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [13, 0, -11]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, -11]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, 9]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, 7]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, 5]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, 3]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, 1]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, -1]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, -3]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, -5]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, -7]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-15, 0, -9]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, 9]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, 7]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, 5]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, 3]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, -1]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, -3]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, -5]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, -7]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [15, 0, -9]},
{"kind": "tomb", "size": [6, 1.563, 2.609], "center": [1, 0, 0]},
{"kind": "tomb", "size": [6, 0.75, 2.576], "center": [1, 0.761, 0]},
{"kind": "tomb", "size": [1.739, 1.042, 4], "center": [1, 0, 0]},
{"kind": "pillar", "size": [1.7, 4, 3.4], "center": [-7, 2, 4]},
{"kind": "pillar", "size": [1.7, 4, 3.4], "center": [9, 2, 4]},
{"kind": "pillar", "size": [1.7, 4, 3.4], "center": [-7, 2, -6]},
{"kind": "pillar", "size": [1.7, 4, 3.4], "center": [9, 2, -6]},
{"kind": "gate", "size": [0.95, 1.95, 0.95], "center": [-5, 0.975, 9]},
{"kind": "gate", "size": [1.3, 0.45, 1.3], "center": [-5, 0.225, 9]},
{"kind": "tavern", "size": [0.95, 1.95, 0.95], "center": [13, 0.975, 3]},
{"kind": "tavern", "size": [1.3, 0.45, 1.3], "center": [13, 0.225, 3]},
{"kind": "urn", "size": [1.8, 1.5, 1.8], "center": [5, 0.75, -3]},
{"kind": "bone", "size": [1.8, 0.85, 3.6], "center": [-11, 0.425, -8]},
{"kind": "cracked", "size": [1.8, 0.85, 1.8], "center": [-9, 0.425, -9]},
{"kind": "tomb", "size": [0.95, 1.95, 0.95], "center": [-3, 0.975, 1]},
{"kind": "tomb", "size": [1.3, 0.45, 1.3], "center": [-3, 0.225, 1]},
{"kind": "tomb", "size": [0.95, 1.95, 0.95], "center": [5, 0.975, 1]},
{"kind": "tomb", "size": [1.3, 0.45, 1.3], "center": [5, 0.225, 1]},
{"kind": "buttress", "size": [1.7, 2.2, 1.7], "center": [-11, 1.1, 9]},
{"kind": "buttress", "size": [1.7, 2.2, 1.7], "center": [-9, 1.1, 9]},
{"kind": "buttress", "size": [1.7, 2.2, 1.7], "center": [3, 1.1, 9]},
{"kind": "buttress", "size": [1.7, 2.2, 1.7], "center": [7, 1.1, 9]},
{"kind": "buttress", "size": [1.7, 2.2, 1.7], "center": [9, 1.1, 9]}
]
}
64 changes: 64 additions & 0 deletions extensions/renderers/unity/boxes/tavern_kit_v1_boxes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"version": 1,
"ortho": 10.5224,
"cols": 14, "rows": 11,
"provenance": "kit-derived (build_room_kit ExportBoxes): per-mass renderer bounds of KitRoom_tavern",
"boxes": [
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-13, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-11, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-9, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-7, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-5, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-3, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [-1, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [3, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [5, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [7, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [9, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [11, 0, 10]},
{"kind": "wallback", "size": [2, 5.4, 1.4], "center": [13, 0, 10]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-11, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-9, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-7, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-5, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-3, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [-1, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [1, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [3, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [5, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [7, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [9, 0, -10]},
{"kind": "parapet", "size": [2, 0.55, 1.4], "center": [11, 0, -10]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [13, 0, -10]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, 8]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, 6]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, 4]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, 2]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, 0]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, -2]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, -4]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, -6]},
{"kind": "parapet", "size": [1.4, 0.55, 2], "center": [-13, 0, -8]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [13, 0, 8]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [13, 0, 6]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [13, 0, 4]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [13, 0, 2]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [13, 0, -2]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [13, 0, -4]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [13, 0, -6]},
{"kind": "wallright", "size": [1.4, 5.4, 2], "center": [13, 0, -8]},
{"kind": "bar", "size": [7.2, 1.4, 1.8], "center": [-6, 0.7, 6]},
{"kind": "barrel", "size": [1.8, 1.5, 1.8], "center": [-9, 0.75, 8]},
{"kind": "barrel", "size": [1.8, 1.5, 1.8], "center": [-7, 0.75, 8]},
{"kind": "hearth", "size": [3.6, 1.4, 1.8], "center": [8, 0.7, 8]},
{"kind": "table", "size": [1.8, 1.4, 3.6], "center": [-5, 0.7, -1]},
{"kind": "table", "size": [1.8, 1.4, 3.6], "center": [5, 0.7, 1]},
{"kind": "table", "size": [3.6, 1.4, 1.8], "center": [2, 0.7, -4]},
{"kind": "table", "size": [3.6, 1.4, 1.8], "center": [10, 0.7, -4]},
{"kind": "candle", "size": [0.95, 1.95, 0.95], "center": [3, 0.975, 8]},
{"kind": "candle", "size": [1.3, 0.45, 1.3], "center": [3, 0.225, 8]},
{"kind": "candle", "size": [0.95, 1.95, 0.95], "center": [11, 0.975, 4]},
{"kind": "candle", "size": [1.3, 0.45, 1.3], "center": [11, 0.225, 4]}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions extensions/renderers/unity/plates_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"pitch": 30,
"yaw": 45
},
"boxes": "boxes/crypt_v36_boxes.json",
"boxes": "boxes/crypt_kit_v1_boxes.json",
"effects": [
{
"type": "fire_medium",
Expand Down Expand Up @@ -49,7 +49,7 @@
}
],
"_effects_comment": "Animated fire over the four painted brazier fires (geometry brazier cells; bowls sit ~1.2u up the stem). Tune scale/y at the sandbox eyeball if the flame floats or washes the paint.",
"_provenance": "KIT-CRYPT v1 (2026-07-23, #83/#84 nav-truth spike): 3D-FIRST CERTIFIED CHAIN \u2014 geometry crypt_v36 -> build_room_kit scene (footprint SEG GATE 100.00%, 0/192 disagreements, qa/evidence/kit-crypt/) -> kit 3D depth -> flux depth-CN base seed 12346 (recall 0.9752, asset_qM9R3tuRH4sceUrVjCoLdPRk) -> Gemini 3.0 Pro edit (model_google-gemini-pro-image-editing, critique-targeted detail prompt, job_Lmhssjh7iWnHsUKY1dhnHB4m) -> phase-corr ALIGNED dx=0,dy=0 vs base (qa/styled_align_check.py) -> geometric void composite (seg-frame mask). Blind panel 7 vs control 8 (delta -1.0, in-band; wf_89967920). Collision truth UNCHANGED (same geometry/walkmask/boxes as crypt_v36). NOTE: model_google-gemini-pro-image-editing pending model-registry allowlist (owner sign-off)."
"_provenance": "KIT-CRYPT v1 (2026-07-23, #83/#84 nav-truth spike): 3D-FIRST CERTIFIED CHAIN \u2014 geometry crypt_v36 -> build_room_kit scene (footprint SEG GATE 100.00%, 0/192 disagreements, qa/evidence/kit-crypt/) -> kit 3D depth -> flux depth-CN base seed 12346 (recall 0.9752, asset_qM9R3tuRH4sceUrVjCoLdPRk) -> Gemini 3.0 Pro edit (model_google-gemini-pro-image-editing, critique-targeted detail prompt, job_Lmhssjh7iWnHsUKY1dhnHB4m) -> phase-corr ALIGNED dx=0,dy=0 vs base (qa/styled_align_check.py) -> geometric void composite (seg-frame mask). Blind panel 7 vs control 8 (delta -1.0, in-band; wf_89967920). Collision truth UNCHANGED (same geometry/walkmask/boxes as crypt_v36). NOTE: model_google-gemini-pro-image-editing pending model-registry allowlist (owner sign-off). SIDECAR 2026-07-23: kit-derived boxes (ExportBoxes, 73 per-mass true bounds: parapets 0.55u, pillars/tomb/buttresses at real heights) replacing the authored crypt_v36 volumes -- silhouette bands now hug the paint."

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Correct the stale “boxes unchanged” provenance. Both entries replace the occluder sidecar, so claiming the prior boxes are unchanged makes the release evidence self-contradictory. Preserve that engine geometry/walkmask collision is unchanged, but explicitly state that the visual occluder sidecar changed. Confidence: 100%.

  • extensions/renderers/unity/plates_manifest.json#L52-L52: replace same geometry/walkmask/boxes as crypt_v36 with wording that distinguishes unchanged geometry/walkmask from the new kit-derived boxes.
  • extensions/renderers/unity/plates_manifest.json#L82-L82: replace tavern_v2 geometry/walkmask/boxes with the same distinction.
📍 Affects 1 file
  • extensions/renderers/unity/plates_manifest.json#L52-L52 (this comment)
  • extensions/renderers/unity/plates_manifest.json#L82-L82
🤖 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 `@extensions/renderers/unity/plates_manifest.json` at line 52, The provenance
entries at extensions/renderers/unity/plates_manifest.json lines 52-52 and 82-82
incorrectly claim the collision boxes are unchanged. Update both entries to
state that engine geometry and walkmask collision remain unchanged while the
visual occluder sidecar now uses new kit-derived boxes; preserve the existing
provenance context.

},
"camp_clearing_night": {
"plate": "plates/camp_clearing_night_truegrey_v1.png",
Expand All @@ -72,14 +72,14 @@
"_sync_comment": "MIRRORED as camp_clearing for the adventure fixture \u2014 see that entry; the sync lint in test_seed_adventure_demo pins them identical."
},
"tavern": {
"plate": "plates/tavern_kit_v1_registered.png",
"plate": "plates/tavern_kit_v2_registered.png",
"cameraPin": {
"ortho": 10.5224,
"pitch": 30,
"yaw": 45
},
"boxes": "boxes/tavern_v2_boxes.json",
"_provenance": "KIT-TAVERN v1 (2026-07-23, #83 replication proof): SAME certified chain as KIT-CRYPT v1 \u2014 geometry tavern_v2 -> kit scene (seg gate 100.00% FIRST TRY, 0/154) -> kit 3D depth -> flux base seed 12345 (recall 0.9737+, asset_G5UBNVwMchoG84wPSFiBEsAZ) -> Gemini 3.0 Pro edit c2 w/ FURNITURE-IDENTITY grounding (job_UTwT9WJkbvZpuveXDoMso8Eh) -> phase-corr ALIGNED dx=0 -> seg-mask void composite. Blind panel 7 vs control 8 (delta -1.0 in-band; c1 without furniture grounding was 6/-2.0 \u2014 the grounding clause is load-bearing). Collision truth UNCHANGED (tavern_v2 geometry/walkmask/boxes)."
"boxes": "boxes/tavern_kit_v1_boxes.json",
"_provenance": "KIT-TAVERN v1 (2026-07-23, #83 replication proof): SAME certified chain as KIT-CRYPT v1 \u2014 geometry tavern_v2 -> kit scene (seg gate 100.00% FIRST TRY, 0/154) -> kit 3D depth -> flux base seed 12345 (recall 0.9737+, asset_G5UBNVwMchoG84wPSFiBEsAZ) -> Gemini 3.0 Pro edit c2 w/ FURNITURE-IDENTITY grounding (job_UTwT9WJkbvZpuveXDoMso8Eh) -> phase-corr ALIGNED dx=0 -> seg-mask void composite. Blind panel 7 vs control 8 (delta -1.0 in-band; c1 without furniture grounding was 6/-2.0 \u2014 the grounding clause is load-bearing). Collision truth UNCHANGED (tavern_v2 geometry/walkmask/boxes). SIDECAR 2026-07-23: kit-derived boxes (ExportBoxes per-mass true bounds; cutaway parapets 0.55u, tables 1.4u true footprints) replacing the authored tavern_v2 chunky volumes \u2014 felt-truth fix for the owner-caught silhouette-everywhere class. V2 2026-07-23: per-object gate (qa/object_align_check.py) caught the c2 edit DELETING table#51 at (10,-4) (0.69 cells; global phase-corr blind to it) -- surgical fix: gemini-pro reference-conditioned re-add (job_ia3dLBuaA4pLup5ynEzb7zB6, seed 12345) -> feathered diff-mask composite (7.3% of frame, rest byte-certified v1) -> global identity dx=0 + PER-OBJECT-ALIGNED 12/12 (table#51 0.13 cells)."
},
"throne_hall": {
"plate": "plates/throne_hall_v1_registered.png",
Expand Down
35 changes: 35 additions & 0 deletions extensions/renderers/unity/scripts/BuildMacOSPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ public static void Build()
// player can runtime-spawn actors for any campaign (not just the baked scene's cast).
EnsurePackaged();

// Kit rooms (build_room_kit.cs) are QA constructions; a capture flow that saves the scene while
// one exists would otherwise ship it inside the player, drawing grey kit masses over every plate.
string[] strippedQARoots = StripQAConstructions();

// --- Player identity (was DefaultCompany/WorldOS-Unity-spike) ---
PlayerSettings.companyName = "worldos";
PlayerSettings.productName = "WorldOSPlayer";
Expand Down Expand Up @@ -259,13 +263,44 @@ public static void Build()
"platform=" + s.platform + "\n" +
"architecture=" + archResult + "\n" +
"alwaysIncludedShaders=" + string.Join(",", includedShaders) + "\n" +
"strippedQARoots=" + (strippedQARoots.Length == 0 ? "(none)" : string.Join(",", strippedQARoots)) + "\n" +
"scenesBuilt=" + string.Join(",", options.scenes) + "\n");

Debug.Log("[BuildMacOSPlayer] DONE result=" + s.result + " errors=" + s.totalErrors
+ " warnings=" + s.totalWarnings + " size=" + s.totalSize + " time=" + s.totalTime
+ " report=" + reportPath);
}

// QA-construction roots that must NEVER ship inside a player build. build_room_kit.cs assembles
// kit rooms as "KitRoom_<roomId>" roots in whatever scene is open; a capture/lighting flow that
// saves the scene mid-session bakes them in, and the built player then renders grey kit masses
// (fallback boxes, brazier plinths, parapets) in front of every plate. Measured three times
// (kit-crypt cleankit trap ×2, kit-tavern 2026-07-23 — the withheld tavern install). The build
// opens the canonical scene EXPLICITLY (also killing the wrong-open-scene trap), strips matching
// roots, saves, and reports them in build-report.txt (strippedQARoots=...).
const string QARootPrefix = "KitRoom_";

static string[] StripQAConstructions()
{
var scene = UnityEditor.SceneManagement.EditorSceneManager.OpenScene(SceneToBuild);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: OpenScene(path) defaults to OpenSceneMode.Single and discards an unsaved current editor scene without a guard

EditorSceneManager.OpenScene(SceneToBuild) with no mode uses OpenSceneMode.Single. This Build() MenuItem runs in the headed editor (the box forbids -batchmode, per the class doc), so if the operator has an unsaved scene open when they invoke Tools/WorldOS/Build/macOS Player, Unity raises the 'Unsaved changes in scene' dialog and the build blocks until dismissed — or, depending on editor settings, silently discards the operator's unsaved work in the open scene. OccluderVerify.cs:41 and W5bWireScene.cs:35 both call OpenScene(path, OpenSceneMode.Single) explicitly; at minimum make the mode explicit here for parity. More importantly, there is no Force/Save check, so this Build entry point can clobber operator work in a different open scene. Consider OpenSceneMode.Single plus a documented precondition or a SaveCurrentModifiedScenesIfUserWantsTo prompt before opening.

Category: Data loss

Why this matters: Build is an operator-facing MenuItem invoked from the headed editor. An unexpected scene swap mid-build is a data-loss surface for whatever the operator was editing.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: StripQAConstructions opens the canonical scene in Single mode, dropping the editor's active scene

StripQAConstructions calls EditorSceneManager.OpenScene(SceneToBuild) with no mode argument, which defaults to OpenSceneMode.Single — it replaces the editor's currently active scene. If a developer invokes Tools/WorldOS/Build/macOS Player (Universal) while editing a different scene with unsaved work, the build silently closes that scene. Use OpenSceneMode.Additive for the strip pass (and remove the stripped roots + the added scene afterward), or document that the build must be run from a clean state. The comment claims this 'opens the canonical scene EXPLICITLY (also killing the wrong-open-scene trap)' but the cost is destroying unsaved editor state on every invocation that hits the build path.

Category: Runtime correctness

Why this matters: A build menu item that silently discards the developer's active scene and unsaved changes is a real workflow hazard on a headed-editor build flow (the BOX.md-forbidden -batchmode path means this runs interactively).

var stripped = new List<string>();
foreach (var go in scene.GetRootGameObjects())
{
if (go != null && go.name.StartsWith(QARootPrefix, StringComparison.Ordinal))
{
stripped.Add(go.name);
UnityEngine.Object.DestroyImmediate(go);
}
}
if (stripped.Count > 0)
{
UnityEditor.SceneManagement.EditorSceneManager.SaveScene(scene);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: StripQAConstructions ignores SaveScene return value; a silent save failure ships contaminated art with strippedQARoots=(none)

EditorSceneManager.SaveScene returns bool and fails non-throwing on read-only files, VCS/OneDrive locks, disk pressure, or a scene path that resolves but is not writable. Here the bool is discarded, so after DestroyImmediate has already mutated the in-memory scene, a failed save (a) leaves the canonical M1CombatV1_canonical.unity dirty on disk as built and (b) still returns the stripped list, so build-report.txt records strippedQARoots= while the on-disk/built scene still contains the roots. The build then proceeds at line 250 against the un-stripped source. Wrap the save: if (!EditorSceneManager.SaveScene(scene)) { Debug.LogError("[BuildMacOSPlayer] SaveScene FAILED after stripping " + SceneToBuild + " — aborting to avoid shipping QA roots"); return; } (or throw) so a failed strip is a hard build stop, not a silent partial.

Category: Release regression

Why this matters: The entire value of this gate is that no KitRoom_* ships. A silent save failure produces a build-report that claims success while the player renders the grey kit masses the PR exists to prevent — the exact kit-tavern contamination, just with a misleading evidence trail.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Strip persists into the tracked source asset as a build side-effect; no smoke/rollback note

SaveScene writes the strip back into Assets/Scenes/M1CombatV1_canonical.unity — a tracked source asset — as an irreversible side effect of Build(). After Build, the canonical scene on disk is permanently altered (the KitRoom_* roots are gone), and a subsequent git status will show the scene changed by a build run. The repo profile asks that scene changes carry explicit rollback and smoke notes; this PR's body should state the strip is destructive to the source scene and that BuildMacOSPlayer is the only recovery path (re-run build_room_kit to re-add, which is the opposite of the gate's intent). Consider writing a timestamped .unity.bak before SaveScene so an operator who ran Build against a scene they did not want stripped can recover without git surgery.

Category: Unity scene/prefab

Why this matters: A build mutating a tracked scene asset without a backup couples release packaging to source-tree mutation; an operator who triggers Build expecting packaging-only behavior silently commits a scene diff.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: StripQAConstructions persists a source-controlled scene file as a build side effect

When stripped.Count > 0 the method calls EditorSceneManager.SaveScene(scene), writing Assets/Scenes/M1CombatV1_canonical.unity — a source-controlled canonical asset — during a build. This can produce an unexpected diff in the scene file (Unity may rewrite metadata/object ordering) that gets committed by accident, and there is no rollback note in the PR despite the repo's high-risk-paths policy requiring explicit rollback notes for Assets/** changes. Prefer destroying the roots in-memory only (the BuildPlayer call at line 250 opens its own copy of the scene from disk for the actual build) and NOT saving the source scene — the build does not require the source .unity to be re-saved, since BuildPlayer serializes from the loaded scene state.

Category: Release regression

Why this matters: Silent mutation of a canonical scene asset during a build is exactly the class of release-regression risk the repo profile flags as high-risk; an unintended scene diff could ship gameplay-changing object state.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: StripQAConstructions persists a destructive SaveScene on the canonical scene asset at build time

StripQAConstructions() opens Assets/Scenes/M1CombatV1_canonical.unity, DestroyImmediate's every root whose name starts with "KitRoom_", then unconditionally calls EditorSceneManager.SaveScene(scene). This mutates the tracked canonical .unity source asset as a side effect of running the build menu item, and the strip predicate is a bare prefix match (QARootPrefix = "KitRoom_") with no allowlist. Today the kit lighting helpers (KitRoom_Fire/KitRoom_TombGlow/KitRoom_CoolKey in build_room_kit.cs:554/561/567) are nested children of the room root, so they are not root objects and survive — but if any future legitimate GameObject is ever placed at the scene ROOT with a KitRoom_ name, this build step will silently destroy it AND commit that deletion to source. The qa_sandbox.py detector (line 99) already maintains a whitelist for those helper prefixes; the stripper does not, so the gate and the stripper are asymmetric. Consider (a) narrowing the strip to the exact contaminant pattern (e.g. KitRoom_) or mirroring the qa_sandbox whitelist, and (b) only saving when a strip actually occurred is already done — but add a one-line guard/comment that this intentionally rewrites the source scene, so the destructive write is not mistaken for a build-output artifact.

Category: Data loss

Why this matters: A build step that silently rewrites the canonical gameplay scene asset is a release-regression/data-loss surface: a contaminant-removal intended for build output instead commits a structural edit to the source-of-truth scene, and the broad prefix makes future false-positive destruction likely.

Debug.LogWarning("[BuildMacOSPlayer] stripped QA construction roots from " + SceneToBuild
+ ": " + string.Join(",", stripped));
}
return stripped.ToArray();
}

// #1674: shaders CombatSurfaceClient resolves at runtime via Shader.Find and that NO asset references, so
// the player build strips them unless they are listed in Graphics -> Always-Included Shaders. The player
// build MUST carry both or the runtime feature (occluder proxies / walk-behind silhouette) silently no-ops
Expand Down
Loading
Loading