diff --git a/AGENTS.md b/AGENTS.md
index 0cca5cc..22783d7 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,63 +1,48 @@
-# AGENTS.md: Universal Principles for CSharp and General Programming
-
-This guide provides universal, intelligent principles and patterns to master C# coding effectively, applicable across any project or repository.
-
-## 🧠 Structured Reasoning
-
-* **Single Responsibility Principle (SRP)**: Every class and method should have one clearly defined responsibility.
-* **Explicit Intent**: Write self-descriptive methods and classes, avoiding ambiguous or overly general names.
-* **Readability First**: Prioritize readability over cleverness. The intent of your code should be immediately clear to others.
-
-## 🎯 Clarity & Explicitness
-
-* Clearly specify the purpose, parameters, and return values of each method using XML documentation comments.
-* Choose names that explicitly describe intent (e.g., `CalculateTotalPrice()` instead of `Calculate()` or `CalcTP()`).
-* Favor descriptive variable names (`customerAge` rather than `ca`).
-
-## 🔄 Iterative Improvement
-
-* Implement incremental changes and continuously validate with unit tests.
-* Regularly refactor code to simplify complexity and improve maintainability.
-* Conduct periodic peer reviews to integrate diverse perspectives and catch overlooked issues.
-
-## 🛡️ Robustness & Safety Nets
-
-* Write unit tests covering critical paths and edge cases to ensure code stability and correctness.
-* Leverage static code analysis tools like Roslyn analyzers and StyleCop to maintain high-quality standards.
-* Use assertions liberally to document and enforce assumptions in code logic.
-
-## 🏗️ Universal Design Patterns
-
-* **Factory & Abstract Factory**: For managing object creation and reducing direct dependencies.
-* **Strategy Pattern**: To encapsulate varying algorithms and make behaviors interchangeable.
-* **Repository Pattern**: For abstracting data layer logic and enhancing testability.
-* **Dependency Injection**: Use constructor injection to clearly define dependencies and improve modularity.
-
-## ♻️ Maintainable Code Habits
-
-* Avoid magic numbers; define constants or configuration settings instead.
-* Keep methods short (ideally fewer than 30 lines) to enhance readability and testability.
-* Organize methods logically within classes (constructors first, public methods next, followed by private methods).
-
-## 🚦 Consistent Coding Style
-
-* Adhere to established naming conventions:
-
- * Methods & Variables: `PascalCase`
- * Private fields & parameters: `camelCase`
- * Constants: `UPPERCASE_WITH_UNDERSCORES`
-* Consistently format your code using tools like `.editorconfig`.
-
-## 📈 Performance Awareness
-
-* Understand the performance implications of collections (prefer using `Dictionary` for key-value lookups over lists).
-* Minimize object allocations, especially within loops or performance-critical paths.
-* Favor efficient data structures and algorithms suited to the task at hand (e.g., HashSets for uniqueness checks).
-
-## 🛠️ Continuous Learning & Reflection
-
-* Periodically review code written previously to identify opportunities for improvement.
-* Stay updated on language features and industry best practices.
-* Learn from established open-source C# projects and communities.
-
-By internalizing these universal principles, you build a solid foundation to become a proficient and thoughtful C# developer.
+# Eclipse Agent Guide
+
+This file is for Codex and other coding agents working in this repository. Keep changes narrow, evidence-led, and specific to Eclipse's V Rising client UI and Bloodcraft bridge runtime.
+
+## Start Here
+
+- Before acting, restate the exact problem, main non-goals, and the condition that should make you stop instead of pushing forward.
+- Check the current branch and worktree before editing. Do not rebase, push, merge, delete, retarget, or rewrite branches unless explicitly asked.
+- Prefer small, local changes that follow the existing Eclipse patterns. Avoid broad rewrites, style-only churn, or generic architecture cleanups.
+- Treat adjacent repos such as Bloodcraft and Emberglass as evidence or integration partners. Do not move their ownership boundaries into Eclipse unless the task explicitly asks for that consumer-side change.
+
+## Build And Verification
+
+- Use this verification ladder unless the task is explicitly docs-only:
+ - `git diff --check`
+ - `dotnet restore Eclipse.csproj`
+ - `dotnet build Eclipse.csproj --configuration Release -p:DeployToClient=false --no-restore`
+- `Eclipse.csproj` can copy build output to a local V Rising client plugin folder when deployment is enabled. Use `-p:DeployToClient=false` for compile checks that should not stage DLLs.
+- Keep Codex tooling, probes, temporary receipts, and agent-only proof artifacts under `.codex/`.
+- Runtime proof helpers and receipts live under `.codex/runtime-proofs/` and `.codex/runs/`; treat those receipts and logs as evidence, not as source files to polish during unrelated tasks.
+
+## V Rising Modding Constraints
+
+- Preserve BepInEx, Harmony, VampireReferenceAssemblies, IL2CPP, and V Rising client lifecycle assumptions unless the task is specifically to change them.
+- Be careful around static initialization, world access, UI canvas/bootstrap timing, client readiness, and hotload/runtime-load entry points. Do not move runtime lookups earlier without proving the startup path still works.
+- Eclipse initializes in stages: plugin load/config/patching first, then game/world readiness before client services and UI behavior are safe. Keep fallback paths explicit when Emberglass is unavailable or not ready.
+- For Bloodcraft or Emberglass bridge work, separate registration, send, fallback, and runtime receipt evidence. Do not treat a queued or suppressed send as proof that the bridge actually delivered.
+- Avoid importing framework behavior from Emberglass or server-side Bloodcraft code wholesale. Eclipse should stay a consumer UI mod unless the task explicitly changes that boundary.
+
+## Release And Metadata Boundaries
+
+- Keep the canonical version plain `X.Y.Z` in `Eclipse.csproj`, `thunderstore.toml`, and the top `CHANGELOG.md` entry.
+- Do not commit branch-derived `-pre` or `-ft.*` versions. Those are CI outputs only.
+- Defer final README, changelog, and Thunderstore wording until after build and focused verification when a feature branch is still being stabilized.
+- For release workflow changes, keep GitHub prerelease and Thunderstore package-version handling distinct.
+
+## Workflow And Review Guidance
+
+- For GitHub Actions changes, prefer minimal reliability fixes and use YAML-aware validation. Do not run `bash -n` against workflow YAML.
+- For PowerShell proof or release scripts, keep edits small and verify the exact script or test harness touched by the change.
+- For UI/runtime changes, prefer source-backed or log-backed evidence over assumptions from history alone.
+
+## Stop Conditions
+
+- Stop if remote or GitHub state cannot be verified for a branch/merge-train task.
+- Stop if the available evidence cannot distinguish Eclipse-owned behavior from Bloodcraft, Emberglass, stale installs, dependency mismatch, or local environment failure.
+- Stop if verification fails in a way that would require broadening beyond the requested scope.
+- Stop before advising public release, Thunderstore publication, or bridge/runtime success when build evidence, logs, or proof receipts do not support the claim.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21d81ce..3c3143f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
## Unreleased
+`1.3.16`
+- hardened attribute UI initialization so runtime-loaded clients defer when the inventory attribute hierarchy is not ready
+- collapsed Emberglass bridge progress receipts to one client log line per config/progress batch
+
`1.3.15`
- added release hygiene helper scripts for changelog/version bump review and metadata updates
- added CI coverage for the release hygiene nudge before build verification
diff --git a/Eclipse.csproj b/Eclipse.csproj
index 14cee2a..23bf62e 100644
--- a/Eclipse.csproj
+++ b/Eclipse.csproj
@@ -4,7 +4,7 @@
enable
io.zfolmt.Eclipse
Eclipse
- 1.3.15
+ 1.3.16
true
true
preview
diff --git a/Services/CanvasService.cs b/Services/CanvasService.cs
index ea0f663..076aaea 100644
--- a/Services/CanvasService.cs
+++ b/Services/CanvasService.cs
@@ -493,16 +493,32 @@ public static bool InitializeAttributeValues(InventorySubMenu inventorySubMenu)
}
*/
- Transform attributeSectionsParent = inventorySubMenu.AttributesParentConsole.transform.parent.parent.GetChild(4).GetChild(0).GetChild(2).GetChild(0);
- var attributeSections = attributeSectionsParent?
+ if (!TryGetAttributeSectionsParent(inventorySubMenu, out Transform attributeSectionsParent))
+ {
+ return false;
+ }
+
+ var attributeSections = attributeSectionsParent
.GetComponentsInChildren(false).Take(1)
- .Concat(attributeSectionsParent.GetComponentsInChildren(false).Skip(2));
+ .Concat(attributeSectionsParent.GetComponentsInChildren(false).Skip(2))
+ .ToList();
+
+ if (attributeSections.Count == 0)
+ {
+ return false;
+ }
// Core.Log.LogWarning($"Found {attributeSections.Count()} attribute sections!");
foreach (CharacterAttributeSection section in attributeSections)
{
- GameObject attributesContainer = section.transform.FindChild("AttributesContainer").gameObject;
+ Transform attributesContainerTransform = section.transform.FindChild("AttributesContainer");
+ if (attributesContainerTransform == null)
+ {
+ return false;
+ }
+
+ GameObject attributesContainer = attributesContainerTransform.gameObject;
var attributeEntries = attributesContainer.transform.GetComponentsInChildren(false);
int index = 0;
@@ -546,11 +562,40 @@ public static bool InitializeAttributeValues(InventorySubMenu inventorySubMenu)
catch (Exception ex)
{
Core.Log.LogError($"Failed to initialize attribute values for section {section.name}: {ex}");
+ return false;
}
}
return true;
}
+ static bool TryGetAttributeSectionsParent(InventorySubMenu inventorySubMenu, out Transform attributeSectionsParent)
+ {
+ attributeSectionsParent = null;
+
+ Transform attributesParent = inventorySubMenu.AttributesParentConsole?.transform;
+ if (attributesParent?.parent?.parent == null)
+ {
+ return false;
+ }
+
+ Transform root = attributesParent.parent.parent;
+ return TryGetChild(root, 4, out Transform child)
+ && TryGetChild(child, 0, out child)
+ && TryGetChild(child, 2, out child)
+ && TryGetChild(child, 0, out attributeSectionsParent);
+ }
+ static bool TryGetChild(Transform parent, int index, out Transform child)
+ {
+ child = null;
+
+ if (parent == null || parent.childCount <= index)
+ {
+ return false;
+ }
+
+ child = parent.GetChild(index);
+ return child != null;
+ }
}
public static class DataHUD
{
diff --git a/Services/EmberglassEclipseBridge.cs b/Services/EmberglassEclipseBridge.cs
index bcb7fb3..24abb72 100644
--- a/Services/EmberglassEclipseBridge.cs
+++ b/Services/EmberglassEclipseBridge.cs
@@ -17,6 +17,7 @@ internal static class EmberglassEclipseBridge
static bool _unavailableLogged;
static bool _clientReadyLogged;
static bool _notReadyLogged;
+ static bool _progressReceiptLogged;
static MethodInfo _sendToServer;
static PropertyInfo _isReady;
static EventInfo _onReady;
@@ -124,6 +125,30 @@ static void OnServerMessagePacket(User sender, EclipseServerMessagePacket packet
return;
}
+ LogReceivedServerMessage(messageKind);
+ }
+
+ static void LogReceivedServerMessage(string messageKind)
+ {
+ if (string.Equals(messageKind, "configs", StringComparison.OrdinalIgnoreCase))
+ {
+ _progressReceiptLogged = false;
+ Core.Log.LogInfo("[EclipseBridge:Emberglass] configs received");
+ return;
+ }
+
+ if (string.Equals(messageKind, "progress", StringComparison.OrdinalIgnoreCase))
+ {
+ if (_progressReceiptLogged)
+ {
+ return;
+ }
+
+ _progressReceiptLogged = true;
+ Core.Log.LogInfo("[EclipseBridge:Emberglass] progress received");
+ return;
+ }
+
Core.Log.LogInfo($"[EclipseBridge:Emberglass] {messageKind} received");
}
diff --git a/thunderstore.toml b/thunderstore.toml
index 1f1ce1f..f3ccaec 100644
--- a/thunderstore.toml
+++ b/thunderstore.toml
@@ -11,7 +11,7 @@ v-rising = ["oakveil-update", "mods", "client"]
[package]
namespace = "zfolmt"
name = "Eclipse"
-versionNumber = "1.3.15"
+versionNumber = "1.3.16"
description = "Client UI for Bloodcraft!"
websiteUrl = "https://github.com/mfoltz/Eclipse"
containsNsfwContent = false