Docs: attribute-swallow root cause + session log; CLAUDE.md gotcha + 6.5 accuracy fixes (net-zero)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-07 21:38:10 -07:00
parent 8baf98622f
commit 5a16acc56d
5 changed files with 96 additions and 16 deletions
@@ -63,7 +63,8 @@ after a playtest gate). **Blender scope: hero props + decals.** No time estimate
> **Gate outcome (2026-07-07 operator playtest):** trunk holds mechanically, but the verdict is *"not cohesive, very
> static, visually boring — comparable games' environments are dynamic and interactable"* + ability upgrades boring +
> the 07-07 harvest shrink/pop never showed on-screen (the pre-flagged PostTransformMatrix-on-root risk is real).
> the 07-07 harvest shrink/pop never showed on-screen (root cause later pinned same day: a swallowed
> `[RuntimeInitializeOnLoadMethod]` attribute — NOT the pre-flagged PTM-on-root risk, which live-verified correct).
> → **Phase 1.5 (World Alive) inserted below; mechanic-changer boons PULLED FORWARD from Phase 3 (Phase 1.7).**
> Explicit operator framing: make the game **look better**, not more "juice" — the code-side hit-feel layer stays as-is.
@@ -110,12 +111,18 @@ attacks/animations/effects**. Art direction deliberately UNDECIDED — lighting
### Stabilize first (bugs, do before the pass)
1. **Node harvest feedback fix:** the shrink/pop drives `PostTransformMatrix` on the ghost ROOT, but node meshes are
render (LEG) children → scale the render children instead (the 07-07 session log pre-flagged exactly this).
**Verify ON-SCREEN this time** — the operator's eyes are the test for skinned/scaled visuals.
2. **Collision precision pass:** operator reports collisions imprecise/not working well. Diagnose scope FIRST
(environment collision vs body-blocking vs melee/projectile hit registration — each is a different system) with a
live repro session, then fix. Swept-not-point rules apply to anything hit-reg.
1. ~~Node harvest feedback fix~~ **FIXED (2026-07-07 session B).** Root cause was NOT the pre-flagged
PTM-on-root risk — live inspection proved the Model child properly parented and root-PTM propagation exact
(root PTM 0.783 → child LTW 1.723 = 2.2×0.783). The 07-07 knob edit had **swallowed the
`[RuntimeInitializeOnLoadMethod]` attribute** off `WorldFeelConfig.ResetDefaults``Enabled=false` → the WHOLE
feedback slice (shrink/pop + chips + SFX + micro-punch) silently dead. One-line restore; verified on-screen +
numerically on a live server-spawned node; 455/455. Operator still eyeballs a real harvest in the next playtest.
2. **Collision precision pass — SCOPED (2026-07-07 operator): environment collider FIDELITY.** Collision shapes
don't match the visual meshes (cover rocks etc.) — invisible walls / visual clipping. TODO: audit every
Environment-layer collider (boundary rim, landmark rocks, in-room cover props) and fit them to the render mesh
(tightened primitives or convex mesh colliders); verify against the baked subscene PhysicsWorld (that's where
they live — classic-GameObject views lie). Re-validate the enemy stuck-fix backstop after any shape change
(Depenetrate/tangent-slide was tuned on the old shapes).
### Short-term wins (asset/scene/client layer)
@@ -40,6 +40,7 @@ Driving an AFK run headless is flaky: the buffed player's `Health` is **reset to
## Not freeze-framed (operator eyeball on next playtest — trivial with real input)
- **Node shrink/pop VISUAL** — `NodeFeedbackSystem` ran clean against the 2 nodes but the run-timing never let me catch the shrink on-screen. **One risk to confirm:** the shrink uses `PostTransformMatrix` on the node **root** — this scales the mesh only if the mesh is on the root or on *parented* children. If a node's mesh is an unparented render child, scale the children instead (cheap fix).
- **RESOLVED same day (session B — hypothesis WRONG):** the child is properly parented and root-PTM propagation is exact; the real bug was this session's own knob edit **swallowing the `[RuntimeInitializeOnLoadMethod]` attribute** off `WorldFeelConfig.ResetDefaults``Enabled=false` → the whole feedback slice dead. See [[2026-07-07_Phase15_NodeFeedback_Attribute_Swallow]].
## Next-session intent
Operator playtests the expedition: confirm (1) no stuck stragglers across a few rooms, (2) markers read well / not cluttered, (3) node shrink+pop visible on harvest, (4) tune knobs (`FeelConfig.EnemyMarker*`, `WorldFeelConfig.Node*`/`Chip*`, backstop consts in `EnemyAISystem`). Then bank as a DR if the design sticks.
@@ -0,0 +1,62 @@
---
title: 2026-07-07_Phase15_NodeFeedback_Attribute_Swallow
type: note
permalink: gamevault/07-sessions/2026/2026-07-07-phase15-nodefeedback-attribute-swallow
---
# 2026-07-07 (session B) — Phase 1.5 stabilize: harvest feedback was dead — a swallowed attribute
**Driver:** `/dots-dev` (Small track — client-only static config, no wire/bake change). Operator playtest reported the
harvest hit-effects "don't seem to be working"; this session also landed the roadmap restructure (Phase 1 gate verdict
→ Phase 1.5 World Alive + boons pulled to 1.7, committed `d966813a3`).
## Root cause — NOT the pre-flagged PTM risk
The 07-07 session-A log suspected the `PostTransformMatrix`-on-ghost-ROOT shrink wouldn't reach an unparented render
child. **Live inspection disproved that**: a server-spawned `ResourceNode` ghost (RegionTag overridden to Base so
relevancy kept it near the player) showed the `Model` child properly `Parent`ed (LT.scale 2.2, MMI on child, root
mesh-less), and once enabled the propagation was *exact* — root PTM 0.892 → child LTW 1.962 = 2.2 × 0.892.
The real bug: **the 07-07 "Node* knobs" edit to `WorldFeelConfig.cs` swallowed the
`[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]` attribute** above
`ResetDefaults()` (the diff in commit `cc2e7ad95` shows the attribute+signature lines replaced by the knob block
ending in a zero-indent bare signature). Nothing else calls `ResetDefaults` → every field stayed C# default:
`Enabled=false`, `ChipBurstCount=0`, SFX 0 → **the entire world-feedback slice silently dead** — node shrink/pop,
chip particles, harvest SFX, camera micro-punch. Matches the operator report exactly ("hit effects + some other
stuff"). Second occurrence of the *edit-swallows-adjacent-line* class in two days (07-06 `_portalMat`
comment-swallow NRE).
## Diagnosis harness (reusable)
1. Play; server `execute_code`: find the node prefab (`ResourceNode` + `Prefab`, `IncludePrefab`), `Instantiate`,
`baked.WithPosition(playerPos + offset)`, **`RegionTag{Region=0}`** so region relevancy doesn't cull it at base.
2. Client dump: LEG per-entity `Parent`/`LocalTransform`/`PostTransformMatrix`/`MaterialMeshInfo` + LTW scale.
3. Simulated hits = server-side `Remaining -=` writes (replicates; no player positioning needed); numeric check =
`lerp(NodeMinScale, 1, Remaining/Max)` vs root PTM vs child LTW; screenshot via `ScreenCapture.CaptureScreenshot`
in `execute_code` (async — read the PNG on the next MCP round-trip; never the pausing bridge capture).
## Fix + validation
- One edit: restored the attribute on `WorldFeelConfig.ResetDefaults` (`apply_text_edits` + precondition SHA).
- **L1** console clean (baseline warnings only). **L2** EditMode **455/455**. **L3** fresh Play with NO manual poke:
`Enabled=True ChipBurstCount=12 NodeMinScale=0.35` purely from the attribute; end-to-end on a fresh spawned node —
server 30→20, client root PTM **0.783** (= lerp(0.35,1,20/30) exact), child LTW **1.723** (= 2.2×0.783), node
visibly shrunken on-screen (`scratchpad/node_shrink_fixed.png`).
## Lessons
- **An MCP text edit can swallow an adjacent attribute/comment line** — after editing next to an attributed method,
re-read the surrounding lines (now a CLAUDE.md gotcha; 2 shipped bugs in 2 days from this class).
- **When a whole presentation slice goes silent, probe its static config's `Enabled` in-play first** — one
`execute_code` read beats structural theorizing (the PTM hypothesis was plausible and wrong).
- The [[mcp-screenshot-step-pause-bug]] + no-sleep-poll rules held: hits were injected server-side and read on
subsequent round-trips; no pauses, no freezes.
## Next-session intent
Operator playtest confirms harvest feel on real nodes (knobs: `WorldFeelConfig.Node*`/`Chip*`), then the
**collision-precision live repro** (Phase 1.5 stabilize #2) — scope whether "imprecise collisions" means environment
collision, body-blocking, or melee/projectile hit-reg before touching any system. Then the lighting/atmosphere pass.
Related: [[2026-07-07_Expedition_Enemy_Stuck_Harvest_Feedback]] · [[Iteration_2026-07_CoopHades]] ·
[[DR-044_Expedition_Redesign_Shipped_Demo_Polish]]
@@ -437,3 +437,13 @@ from the deleted samples tree) so the deformation-material rule is still self-co
### Synty HUD skin / HudTheme (verbatim from CLAUDE.md)
- **Synty HUD skin via a build-safe `HudTheme` ★ (DR-024):** a runtime name-string `Resources.Load` of Synty sprites is **build-stripped** → use a curated `HudTheme : ScriptableObject` of serialized refs (`HudTheme.Get()` null-safe, flat fallback). `unityBackgroundImageTintColor` MULTIPLIES; don't set `unitySlice*` on 9-slice sprites (per-element ERROR); Synty sprites may import as **Multiple**`LoadAssetAtPath<Sprite>` null. See [[DR-024_HUD_Synty_Skin_Theme]].
## 2026-07-07b — condensation-history long form + attribute-swallow incident (Phase 1.5 stabilize)
**Trimmed from CLAUDE.md this pass** (pays the new apply_text_edits attribute-swallow gotcha):
- Old condensation-history line, long form: "06-04 → 06-17 (M1END-2 long-form + 6.5 stack swap → archive) · 07-04 (base-mining core-loop bullet + stack-history sentence → archive; DR-044 supersedes) · 07-04b (EB-1/2 · END-1/2 bullets → DR pointers, pays DR-045) · 07-04c (Rukhanka-samples/bake/history/enemy-anim bullets trimmed → archive, pays the DR-046 portal/class/prep additions + Health.Max fix) · 07-06 (Aim-controls + URP-version + VolumeProfile + HDRP-convert → archive; pays the HUMANOID-pipeline correction — the 'Generic skeleton' note was WRONG)."
- Old stack-history sentence: "6.4.7→6.5.0 swap validated green; the 6.6.0a6 transport bug misses 6.5-stable" (DR-002 holds the full story).
- Old maintenance-section sentence: "Design rationale already lives in the per-milestone DRs (`Docs/Vault/07_Sessions/_Decisions/DR-###`)."
**The incident behind the new gotcha:** the 2026-07-07 "Node* knobs" edit to `WorldFeelConfig.cs` (commit `cc2e7ad95`) replaced a span that included the `[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]` attribute above `ResetDefaults()`, leaving a bare zero-indent signature. Nothing else calls `ResetDefaults` → all statics stayed C# defaults (`Enabled=false`, `ChipBurstCount=0`) → the ENTIRE harvest/world-feedback slice (node shrink/pop, chip particles, SFX, camera micro-punch) was silently dead; the operator caught it in the Phase 1 gate playtest. Live diagnosis disproved the session-log's own PTM-on-root hypothesis first (the Model child is properly parented; root PTM 0.783 → child LTW 1.723 = 2.2×0.783, exact). Second edit-swallows-adjacent-line bug in two days (07-06 `_portalMat` comment-swallow NRE). Full write-up: `07_Sessions/2026/2026-07-07_Phase15_NodeFeedback_Attribute_Swallow.md`.