-
Mars.P authored
* Add end-to-end ProcessAsync test for transient-pause (required + non-required) The P1b transient-pause fix (#434) was covered only compositionally: the unit tests mock the phase to throw the transient directly, and HalibutResumeReattachTests calls the strategy directly — neither runs the real ExecuteSingleActionAsync per-action catch THROUGH the runner to the pause outcome. The non-required path (no per-target catch) was the gap the adversarial review flagged. This drives the REAL pipeline: IDeploymentTaskExecutor.ProcessAsync over a seeded deployment (KubernetesAgent target, so the real HalibutMachineExecutionStrategy records the in-flight pointer), with only the Halibut RPC transport faked (GetStatus throws a transient HalibutClientException). It asserts, for BOTH required and non-required steps: task Paused (not Failed), checkpoint preserved, and the in-flight pointer preserved. Red-green verified: with the ExecuteSingleActionAsync transient catch neutered, the NON-required case fails (Paused → Failed + checkpoint deleted) — the exact swallow bug — while the required case still passes (the per-target catch covers it), confirming the test specifically guards the non-required propagation the fix added. * Tighten transient-pause E2E: typed pointer reader + permanent-failure contrast Replace the brittle Contains("\"t\"") substring with the production typed reader InFlightScriptMap.TryGet(json, DispatchSlot(...)) asserting the preserved pointer holds the EXACT ScriptTicket the strategy dispatched (captured in the fake) — pins slot identity + ticket value and survives a JsonPropertyName rename. Add a permanent-failure contrast case: the same seeded path with a permanent Halibut subtype (ServiceNotFoundHalibutClientException) must Fail terminally + delete the checkpoint, so the Paused rows read as "Paused iff transient" and the transient/permanent boundary is pinned end-to-end, not just in the predicate's own unit test.Mars.P authored* Add end-to-end ProcessAsync test for transient-pause (required + non-required) The P1b transient-pause fix (#434) was covered only compositionally: the unit tests mock the phase to throw the transient directly, and HalibutResumeReattachTests calls the strategy directly — neither runs the real ExecuteSingleActionAsync per-action catch THROUGH the runner to the pause outcome. The non-required path (no per-target catch) was the gap the adversarial review flagged. This drives the REAL pipeline: IDeploymentTaskExecutor.ProcessAsync over a seeded deployment (KubernetesAgent target, so the real HalibutMachineExecutionStrategy records the in-flight pointer), with only the Halibut RPC transport faked (GetStatus throws a transient HalibutClientException). It asserts, for BOTH required and non-required steps: task Paused (not Failed), checkpoint preserved, and the in-flight pointer preserved. Red-green verified: with the ExecuteSingleActionAsync transient catch neutered, the NON-required case fails (Paused → Failed + checkpoint deleted) — the exact swallow bug — while the required case still passes (the per-target catch covers it), confirming the test specifically guards the non-required propagation the fix added. * Tighten transient-pause E2E: typed pointer reader + permanent-failure contrast Replace the brittle Contains("\"t\"") substring with the production typed reader InFlightScriptMap.TryGet(json, DispatchSlot(...)) asserting the preserved pointer holds the EXACT ScriptTicket the strategy dispatched (captured in the fake) — pins slot identity + ticket value and survives a JsonPropertyName rename. Add a permanent-failure contrast case: the same seeded path with a permanent Halibut subtype (ServiceNotFoundHalibutClientException) must Fail terminally + delete the checkpoint, so the Paused rows read as "Paused iff transient" and the transient/permanent boundary is pinned end-to-end, not just in the predicate's own unit test.
Loading