Two EcoReplay BodySerializer tests fail on clean checkout (ArgumentException: Can not convert Object to String) #67

Closed
opened 2026-07-05 05:42:49 +00:00 by coilysiren · 3 comments
Owner

Problem

ward exec test-mod-replay (mods/replay/tests/EcoReplay.Tests.csproj) has 2 failing tests on a pristine checkout of main, unrelated to any recent change:

  • BodySerializerTests.NamedEntity_IsCollapsedToItsName
  • BodySerializerTests.DeeplyNestedEntityGraph_DoesNotRecurse

Both fail with System.ArgumentException : Can not convert Object to String. (7 passed, 2 failed, 9 total).

Context

Found while validating the Eco.ReferenceAssemblies pin bump in #66. The failures are not caused by that change: the test project compiles only ../src/BodySerializer.cs against Newtonsoft.Json alone (no Eco.ReferenceAssemblies reference), and both failures reproduce on the clean pre-change tree. The CI mods compile gate (make build-mods, #60) does not run these unit tests, so they fail silently outside CI.

Repro

ward exec test-mod-replay
# Failed!  - Failed: 2, Passed: 7, Skipped: 0, Total: 9

Ask

Fix BodySerializer (or the tests) so test-mod-replay is green, and consider wiring test-mod-replay into the CI mods job so replay regressions are gated, not just compile errors.

Refs

Discovered during #66 (Eco pin audit).

## Problem `ward exec test-mod-replay` (`mods/replay/tests/EcoReplay.Tests.csproj`) has **2 failing tests on a pristine checkout** of `main`, unrelated to any recent change: - `BodySerializerTests.NamedEntity_IsCollapsedToItsName` - `BodySerializerTests.DeeplyNestedEntityGraph_DoesNotRecurse` Both fail with `System.ArgumentException : Can not convert Object to String.` (7 passed, 2 failed, 9 total). ## Context Found while validating the `Eco.ReferenceAssemblies` pin bump in #66. The failures are **not** caused by that change: the test project compiles only `../src/BodySerializer.cs` against Newtonsoft.Json alone (no `Eco.ReferenceAssemblies` reference), and both failures reproduce on the clean pre-change tree. The CI `mods` compile gate (`make build-mods`, #60) does not run these unit tests, so they fail silently outside CI. ## Repro ``` ward exec test-mod-replay # Failed! - Failed: 2, Passed: 7, Skipped: 0, Total: 9 ``` ## Ask Fix `BodySerializer` (or the tests) so `test-mod-replay` is green, and consider wiring `test-mod-replay` into the CI `mods` job so replay regressions are gated, not just compile errors. ## Refs Discovered during #66 (Eco pin audit).
Author
Owner

Director surface (read-only) - grounding for the engineer run.

Reproduced on a clean main: dotnet test mods/replay/tests/EcoReplay.Tests.csproj -> 2 failed / 7 passed, both System.ArgumentException : Can not convert Object to String:

  • BodySerializerTests.NamedEntity_IsCollapsedToItsName
  • BodySerializerTests.DeeplyNestedEntityGraph_DoesNotRecurse

The test project compiles only ../src/BodySerializer.cs against Newtonsoft.Json (no Eco.ReferenceAssemblies), so the fix is fully headless and self-verifying - no live server, no Eco SDK. The make build-mods gate does not run these unit tests, which is why they fail silently.

Done-condition: ward exec test-mod-replay (or dotnet test on that project) green on main.

**Director surface (read-only) - grounding for the engineer run.** Reproduced on a clean `main`: `dotnet test mods/replay/tests/EcoReplay.Tests.csproj` -> **2 failed / 7 passed**, both `System.ArgumentException : Can not convert Object to String`: - `BodySerializerTests.NamedEntity_IsCollapsedToItsName` - `BodySerializerTests.DeeplyNestedEntityGraph_DoesNotRecurse` The test project compiles only `../src/BodySerializer.cs` against Newtonsoft.Json (no `Eco.ReferenceAssemblies`), so the fix is **fully headless and self-verifying** - no live server, no Eco SDK. The `make build-mods` gate does not run these unit tests, which is why they fail silently. Done-condition: `ward exec test-mod-replay` (or `dotnet test` on that project) green on `main`.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-eco-app-67 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-06T03:14:52Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-gaming/eco-app#67 · branch issue-67 · driver claude · workflow direct-main
  • Run: engineer-claude-eco-app-67 · ward v0.413.0 · dispatched 2026-07-06T03:14:52Z
  • Comment thread: 1 included in the pre-flight read, 0 stripped (ward's own automated comments).

Issue body as seeded:

## Problem

`ward exec test-mod-replay` (`mods/replay/tests/EcoReplay.Tests.csproj`) has **2 failing tests on a pristine checkout** of `main`, unrelated to any recent change:

- `BodySerializerTests.NamedEntity_IsCollapsedToItsName`
- `BodySerializerTests.DeeplyNestedEntityGraph_DoesNotRecurse`

Both fail with `System.ArgumentException : Can not convert Object to String.` (7 passed, 2 failed, 9 total).

## Context

Found while validating the `Eco.ReferenceAssemblies` pin bump in #66. The failures are **not** caused by that change: the test project compiles only `../src/BodySerializer.cs` against Newtonsoft.Json alone (no `Eco.ReferenceAssemblies` reference), and both failures reproduce on the clean pre-change tree. The CI `mods` compile gate (`make build-mods`, #60) does not run these unit tests, so they fail silently outside CI.

## Repro

` ` `
ward exec test-mod-replay
# Failed!  - Failed: 2, Passed: 7, Skipped: 0, Total: 9
` ` `

## Ask

Fix `BodySerializer` (or the tests) so `test-mod-replay` is green, and consider wiring `test-mod-replay` into the CI `mods` job so replay regressions are gated, not just compile errors.

## Refs

Discovered during #66 (Eco pin audit).

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.413.0).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-eco-app-67` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-06T03:14:52Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-gaming/eco-app#67` · branch `issue-67` · driver `claude` · workflow `direct-main` - **Run:** `engineer-claude-eco-app-67` · ward `v0.413.0` · dispatched `2026-07-06T03:14:52Z` - **Comment thread:** 1 included in the pre-flight read, 0 stripped (ward's own automated comments). - included: @coilysiren (2026-07-06T03:13:19Z) **Issue body as seeded:** ``` ## Problem `ward exec test-mod-replay` (`mods/replay/tests/EcoReplay.Tests.csproj`) has **2 failing tests on a pristine checkout** of `main`, unrelated to any recent change: - `BodySerializerTests.NamedEntity_IsCollapsedToItsName` - `BodySerializerTests.DeeplyNestedEntityGraph_DoesNotRecurse` Both fail with `System.ArgumentException : Can not convert Object to String.` (7 passed, 2 failed, 9 total). ## Context Found while validating the `Eco.ReferenceAssemblies` pin bump in #66. The failures are **not** caused by that change: the test project compiles only `../src/BodySerializer.cs` against Newtonsoft.Json alone (no `Eco.ReferenceAssemblies` reference), and both failures reproduce on the clean pre-change tree. The CI `mods` compile gate (`make build-mods`, #60) does not run these unit tests, so they fail silently outside CI. ## Repro ` ` ` ward exec test-mod-replay # Failed! - Failed: 2, Passed: 7, Skipped: 0, Total: 9 ` ` ` ## Ask Fix `BodySerializer` (or the tests) so `test-mod-replay` is green, and consider wiring `test-mod-replay` into the CI `mods` job so replay regressions are gated, not just compile errors. ## Refs Discovered during #66 (Eco pin audit). ``` Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.413.0). </details> <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - BodySerializer now retypes summarized props to object so sealed entities collapse to their name; test-mod-replay wired into the CI mods job; all 9 replay tests green on main (a4551e0).

The diagnosis was the whole job here. The symptom (Can not convert Object to String) pointed at the tests, but a top-level-class probe of the exact same code serialized "Actor":"Bob" correctly, so the bug hid behind one keyword: the tests' FakeEntity is private **sealed** class. Newtonsoft has a quiet optimization where a sealed property-type contract is treated as final, so it skips re-resolving the contract from the value our SummaryValueProvider actually returns, and serializes the summary string against the sealed entity's object contract, emitting {}. That fought back for a while, because everything about the resolver looked right and the value provider genuinely returned the right string.

What made me fairly confident in the fix rather than nervous: sealed is the common case for real Eco entities, so this wasn't a test artifact, it was a live recorder bug dropping named references to empty objects. Retyping each summarized property to object defeats the sealed shortcut cleanly, the real mod still compiles against Eco.ReferenceAssemblies, and I also wired test-mod-replay into CI (sharing the compile gate's NuGet-egress retry loop) so this class of behavioural regression can't pass silently again.

One rough edge worth a possible follow-up: the mods job now does two NuGet restores (compile + test) behind separate 3x retry loops. It's correct but a little slow on the flaky runner. If egress keeps biting, folding both into one restore or an in-cluster NuGet proxy (already flagged in #69) would be the durable move.

WARD-OUTCOME: done - BodySerializer now retypes summarized props to `object` so sealed entities collapse to their name; test-mod-replay wired into the CI mods job; all 9 replay tests green on main (a4551e0). The diagnosis was the whole job here. The symptom (`Can not convert Object to String`) pointed at the tests, but a top-level-class probe of the exact same code serialized `"Actor":"Bob"` correctly, so the bug hid behind one keyword: the tests' `FakeEntity` is `private **sealed** class`. Newtonsoft has a quiet optimization where a sealed property-type contract is treated as final, so it skips re-resolving the contract from the value our `SummaryValueProvider` actually returns, and serializes the summary string against the sealed entity's object contract, emitting `{}`. That fought back for a while, because everything about the resolver *looked* right and the value provider genuinely returned the right string. What made me fairly confident in the fix rather than nervous: sealed is the common case for real Eco entities, so this wasn't a test artifact, it was a live recorder bug dropping named references to empty objects. Retyping each summarized property to `object` defeats the sealed shortcut cleanly, the real mod still compiles against Eco.ReferenceAssemblies, and I also wired `test-mod-replay` into CI (sharing the compile gate's NuGet-egress retry loop) so this class of behavioural regression can't pass silently again. One rough edge worth a possible follow-up: the mods job now does two NuGet restores (compile + test) behind separate 3x retry loops. It's correct but a little slow on the flaky runner. If egress keeps biting, folding both into one restore or an in-cluster NuGet proxy (already flagged in #69) would be the durable move.
Sign in to join this conversation.
No description provided.