diff --git a/conductor/workflow.md b/conductor/workflow.md index 9926069e..06f76274 100644 --- a/conductor/workflow.md +++ b/conductor/workflow.md @@ -409,6 +409,8 @@ The fix is **defer-not-catch**: track a one-shot "ready" flag in instance state; When designing any method that calls into `imgui.*` (or similar native libs), ask: "Can this be called before ImGui is fully initialized?" If yes, add a defer-not-catch guard. +**Sentinel type contract.** When implementing a defer-not-catch guard, the early-return sentinel value must match the type contract of the downstream consumer. For `WorkspaceProfile.ini_content: str` (in this codebase), the sentinel must be `""` (str), not `b""` (bytes) — `tomli_w` rejects bytes (`TypeError: Object of type 'bytes' is not TOML serializable`), and `imgui.load_ini_settings_from_memory(ini_data: str, ...)` also expects `str`. A previous version of this fix used `b""` and silently broke the save flow via a `TypeError` raised by `tomli_w.dump`; tests passed unit-test-wise but failed in the live_gui save+load round-trip. The fix was a 1-character change (`b""` → `""`). The regression test in `tests/test_workspace_profile_serialization.py` encodes this contract. + ### Test Failure Bisect Anchors (Theme Track) When debugging test failures introduced by a theming/visual change, use the following bisect anchors: diff --git a/docs/guide_gui_2.md b/docs/guide_gui_2.md index 634ef1e1..fe28a958 100644 --- a/docs/guide_gui_2.md +++ b/docs/guide_gui_2.md @@ -419,6 +419,8 @@ The fix uses a **defer-not-catch** pattern: a one-shot `_ini_capture_ready` flag This pattern unblocks 4-5 live_gui tests that were crashing the GUI subprocess during the first render frames after a `save_workspace_profile` Hook API callback. See [guide_testing.md](guide_testing.md#known-gotchas-2026-06-05) for the broader pattern and how to recognize these crashes. +**Sentinel type contract.** When implementing a defer-not-catch guard, the early-return sentinel value must match the type contract of the downstream consumer. For `WorkspaceProfile.ini_content: str` (in this codebase), the sentinel must be `""` (str), not `b""` (bytes) — `tomli_w` rejects bytes (`TypeError: Object of type 'bytes' is not TOML serializable`), and `imgui.load_ini_settings_from_memory(ini_data: str, ...)` also expects `str`. A previous version of this fix used `b""` and silently broke the save flow via a `TypeError` raised by `tomli_w.dump`; tests passed unit-test-wise but failed in the live_gui save+load round-trip. The fix was a 1-character change (`b""` → `""`). The regression test in `tests/test_workspace_profile_serialization.py` encodes this contract. + --- ## See Also diff --git a/docs/guide_testing.md b/docs/guide_testing.md index fc59b465..0f521d48 100644 --- a/docs/guide_testing.md +++ b/docs/guide_testing.md @@ -640,6 +640,8 @@ The first call (during initial startup) returns a safe empty profile and flips t See `src/gui_2.py:601-606` for the canonical implementation. This pattern unblocks 4-5 live_gui tests that were crashing the GUI subprocess during the first render frames after `_capture_workspace_profile` was invoked by the test (typically via a `save_workspace_profile` Hook API callback). +**Sentinel type contract.** When implementing a defer-not-catch guard, the early-return sentinel value must match the type contract of the downstream consumer. For `WorkspaceProfile.ini_content: str` (in this codebase), the sentinel must be `""` (str), not `b""` (bytes) — `tomli_w` rejects bytes (`TypeError: Object of type 'bytes' is not TOML serializable`), and `imgui.load_ini_settings_from_memory(ini_data: str, ...)` also expects `str`. A previous version of this fix used `b""` and silently broke the save flow via a `TypeError` raised by `tomli_w.dump`; tests passed unit-test-wise but failed in the live_gui save+load round-trip. The fix was a 1-character change (`b""` → `""`). The regression test in `tests/test_workspace_profile_serialization.py` encodes this contract. + --- ## See Also