ElementRegistry incompatibility lists reference unregistered elements (H→F/Cl, O→Na/K) #792

Closed
opened 2026-07-22 06:24:38 +00:00 by spikerj · 2 comments
Owner

Found by the coverage wave (spikersoft-backend PR #454) while writing ElementRegistryTests.

SpikerSoft.GameServer/Data/Elements.cs registers 22 elements, but two IncompatibleWith lists reference symbols that are never registered:

  • H.IncompatibleWith = ["O", "F", "Cl"] — F and Cl don't exist in the registry
  • O.IncompatibleWith = ["H", "Na", "K"] — Na and K don't exist in the registry

Consequences today:

  • ElementRegistry.AreCompatible("H", "F") returns false, but only because Get("F") is null (unknown-element path), not because of the declared incompatibility — the intent is ambiguous.
  • GetIncompatibleElements("H") returns symbols (F, Cl) that Get() can't resolve, so callers that look up the returned symbols get nulls.

Fix options: register F/Cl/Na/K, or prune the dangling references. Until then, ElementRegistryTests.GetAll_KnownDanglingIncompatibilityReferences_ArePinned pins the exact dangling set and will fail when this is fixed (update the test to the strict invariant then).

Found by the coverage wave (spikersoft-backend PR #454) while writing `ElementRegistryTests`. `SpikerSoft.GameServer/Data/Elements.cs` registers 22 elements, but two `IncompatibleWith` lists reference symbols that are never registered: - `H.IncompatibleWith = ["O", "F", "Cl"]` — **F and Cl don't exist** in the registry - `O.IncompatibleWith = ["H", "Na", "K"]` — **Na and K don't exist** in the registry Consequences today: - `ElementRegistry.AreCompatible("H", "F")` returns `false`, but only because `Get("F")` is null (unknown-element path), not because of the declared incompatibility — the intent is ambiguous. - `GetIncompatibleElements("H")` returns symbols (`F`, `Cl`) that `Get()` can't resolve, so callers that look up the returned symbols get nulls. Fix options: register F/Cl/Na/K, or prune the dangling references. Until then, `ElementRegistryTests.GetAll_KnownDanglingIncompatibilityReferences_ArePinned` pins the exact dangling set and will fail when this is fixed (update the test to the strict invariant then).
Author
Owner

Audited against origin/master — STILL BROKEN, verdict unchanged, but two details in the body have drifted.

The defect holds. SpikerSoft.GameServer/Data/Elements.cs:126 — H → ["O","F","Cl"]; :186 — O → ["H","Li","Na","K","Mg"]. Grepping for Symbol = "F", "Cl", "Na", "K" returns nothing, so all four referenced elements are still unregistered.

Note correction 1 — the O snippet is stale. The ticket quotes O.IncompatibleWith = ["H","Na","K"]; the code now reads ["H","Li","Na","K","Mg"]. Li and Mg are registered, so the dangling set is still exactly Na and K and the verdict is unaffected — but the quoted snippet no longer matches, and someone diffing against it would be confused.

Note correction 2 — the element count may be off by one. The body says "22 elements"; counting Symbol = entries gives 23. Most likely the author deliberately excluded the He3 isotope entry at :457. Flagging rather than asserting an error.

Worth knowing: the pin test does not carry the drift. ElementRegistryTests.cs:41-53 computes the dangling set dynamically via .Where(other => !all.ContainsKey(other)) rather than hard-coding the three-entry list. So the test stays correct as the registry evolves — the staleness is ticket-only, which is the right way round.

Priority context — this one is latent. AreCompatible (:516) and GetIncompatibleElements (:528) have no production caller; they appear only at their declarations and in tests. So no gameplay path currently consumes the bad data.

From the same eleven-ticket sweep: #792, #808 and #840 are latent (no production caller), while #811 (broken AES on a live network path), #793, #794, #795, #797 and #799 are on live paths. If these get worked as a batch, that's the split I'd use to order them.

Audited against `origin/master` — **STILL BROKEN, verdict unchanged, but two details in the body have drifted.** **The defect holds.** `SpikerSoft.GameServer/Data/Elements.cs:126` — `H → ["O","F","Cl"]`; `:186` — `O → ["H","Li","Na","K","Mg"]`. Grepping for `Symbol = "F"`, `"Cl"`, `"Na"`, `"K"` returns nothing, so all four referenced elements are still unregistered. **Note correction 1 — the `O` snippet is stale.** The ticket quotes `O.IncompatibleWith = ["H","Na","K"]`; the code now reads `["H","Li","Na","K","Mg"]`. `Li` and `Mg` *are* registered, so the dangling set is still exactly `Na` and `K` and the verdict is unaffected — but the quoted snippet no longer matches, and someone diffing against it would be confused. **Note correction 2 — the element count may be off by one.** The body says "22 elements"; counting `Symbol =` entries gives 23. Most likely the author deliberately excluded the `He3` isotope entry at `:457`. Flagging rather than asserting an error. **Worth knowing: the pin test does not carry the drift.** `ElementRegistryTests.cs:41-53` computes the dangling set *dynamically* via `.Where(other => !all.ContainsKey(other))` rather than hard-coding the three-entry list. So the test stays correct as the registry evolves — the staleness is ticket-only, which is the right way round. **Priority context — this one is latent.** `AreCompatible` (`:516`) and `GetIncompatibleElements` (`:528`) have **no production caller**; they appear only at their declarations and in tests. So no gameplay path currently consumes the bad data. From the same eleven-ticket sweep: **#792, #808 and #840 are latent** (no production caller), while **#811** (broken AES on a live network path), **#793**, **#794**, **#795**, **#797** and **#799** are on live paths. If these get worked as a batch, that's the split I'd use to order them.
Author
Owner

Migrated to spikerj/spikersoft-backend#538 as part of the umbrella-tracker breakup.

Verified 2026-08-07 against the synced default branch.

  • Code: spikersoft-backend@98102023 — still broken. SpikerSoft.GameServer/Data/Elements.cs:126 — H → ["O", "F", "Cl"]; :186 — O → ["H", "Li", "Na", "K", "Mg"]. rg 'Symbol = "F"|"Cl"|"Na"|"K"' returns nothing, so all four are still unregistered. Body drift: the ticket quotes O.IncompatibleWith = ["H","Na","K"]; the code now also lists Li and Mg, both of which are registered — the dangling set is still exactly F, Cl, Na, K, so the verdict is unaffected, but the quoted snippet no longer matches.
  • Live: Nothing runtime-observable — latent. ElementRegistry.AreCompatible (Elements.cs:516) and GetIncompatibleElements (:528) have no production caller; they appear only at their declarations and in tests. No gameplay path consumes the bad data today.
  • Remaining: Either register F/Cl/Na/K or prune the dangling references, then tighten ElementRegistryTests.GetAll_KnownDanglingIncompatibilityReferences_ArePinned to the strict invariant. (That test computes the dangling set dynamically, so it has not drifted.)

Status: still broken — full detail carried over to the new issue.

Closing here. Work now lives in the repo that holds the fix, so fixes #538 in a PR will
auto-close it on merge. The umbrella tracker keeps cross-repo epics only.

— Opus 5 Agent

Migrated to **spikerj/spikersoft-backend#538** as part of the umbrella-tracker breakup. Verified 2026-08-07 against the synced default branch. - **Code:** `spikersoft-backend@98102023` — still broken. `SpikerSoft.GameServer/Data/Elements.cs:126` — `H → ["O", "F", "Cl"]`; `:186` — `O → ["H", "Li", "Na", "K", "Mg"]`. `rg 'Symbol = "F"|"Cl"|"Na"|"K"'` returns nothing, so all four are still unregistered. **Body drift:** the ticket quotes `O.IncompatibleWith = ["H","Na","K"]`; the code now also lists `Li` and `Mg`, both of which *are* registered — the dangling set is still exactly `F, Cl, Na, K`, so the verdict is unaffected, but the quoted snippet no longer matches. - **Live:** Nothing runtime-observable — **latent**. `ElementRegistry.AreCompatible` (`Elements.cs:516`) and `GetIncompatibleElements` (`:528`) have no production caller; they appear only at their declarations and in tests. No gameplay path consumes the bad data today. - **Remaining:** Either register `F`/`Cl`/`Na`/`K` or prune the dangling references, then tighten `ElementRegistryTests.GetAll_KnownDanglingIncompatibilityReferences_ArePinned` to the strict invariant. (That test computes the dangling set dynamically, so it has not drifted.) Status: still broken — full detail carried over to the new issue. Closing here. Work now lives in the repo that holds the fix, so `fixes #538` in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only. — Opus 5 Agent
Sign in to join this conversation.