[ArtStudio][Bug] Safety gate uses the resident stage executor in resident mode → throws on every image (blocks #368 cutover) #380

Closed
opened 2026-07-05 11:12:47 +00:00 by spikerj · 1 comment
Owner

Bug (found during #378 W5 analysis, confirmed in code; fix built+tested locally, pending push)

ArtPipeArtifactSafetyGate runs SafetyCheck through the injected IArtPipeStageExecutor (ArtifactSafetyGate.cs:56,86). In resident mode (#368 R2), Program.cs:67 makes that the ResidentArtPipeStageExecutor, whose ExecuteAsync (lines 95–99) throws when job.ModelDir != ResidentModel. So a resident image-gen deployment → gate throws on every output → fail-closed (#349) → every image quarantined. Latent today (prod = subprocess mode); hard blocker at the #368 SERVER resident cutover.

Fix (done locally on fix/safety-gate-resident-executor, 666/666 green — awaiting push once git-server disk recovers)

Keyed DI: the gate resolves a dedicated always-subprocess SafetyCheck executor ([FromKeyedServices]), decoupled from the stage IArtPipeStageExecutor. Subprocess mode byte-identical (same singleton; all existing gate tests unchanged); resident mode → dedicated subprocess (no throw); fake mode unchanged. +5 tests incl. failing-before/passing-after resident regression.

Acceptance

  • Resident: gate runs SafetyCheck without ModelDir throw · [x] Subprocess byte-identical · [x] Fail-closed preserved

Severity: High (child-safety; blocks #368 cutover). Related: #368, #349, #362, #378 W5.

## Bug (found during #378 W5 analysis, confirmed in code; fix built+tested locally, pending push) `ArtPipeArtifactSafetyGate` runs `SafetyCheck` through the injected `IArtPipeStageExecutor` (`ArtifactSafetyGate.cs:56,86`). In **resident mode** (#368 R2), `Program.cs:67` makes that the `ResidentArtPipeStageExecutor`, whose `ExecuteAsync` (lines 95–99) **throws** when `job.ModelDir != ResidentModel`. So a resident image-gen deployment → gate throws on every output → fail-closed (#349) → **every image quarantined**. Latent today (prod = subprocess mode); hard blocker at the #368 SERVER resident cutover. ## Fix (done locally on `fix/safety-gate-resident-executor`, 666/666 green — awaiting push once git-server disk recovers) Keyed DI: the gate resolves a dedicated **always-subprocess** `SafetyCheck` executor (`[FromKeyedServices]`), decoupled from the stage `IArtPipeStageExecutor`. Subprocess mode byte-identical (same singleton; all existing gate tests unchanged); resident mode → dedicated subprocess (no throw); fake mode unchanged. +5 tests incl. failing-before/passing-after resident regression. ## Acceptance - [x] Resident: gate runs SafetyCheck without `ModelDir` throw · [x] Subprocess byte-identical · [x] Fail-closed preserved Severity: High (child-safety; blocks #368 cutover). Related: #368, #349, #362, #378 W5.
Author
Owner

Resolved in spikersoft-backend PR #99 (merged to master). Keyed DI gives the safety gate a dedicated always-subprocess SafetyCheck executor — resident mode no longer hits the ModelDir guard, subprocess mode byte-identical (all existing gate tests unchanged), fail-closed preserved. 5 new tests incl. the failing-before/passing-after resident regression. Closing.

Resolved in spikersoft-backend PR #99 (merged to `master`). Keyed DI gives the safety gate a dedicated always-subprocess `SafetyCheck` executor — resident mode no longer hits the `ModelDir` guard, subprocess mode byte-identical (all existing gate tests unchanged), fail-closed preserved. 5 new tests incl. the failing-before/passing-after resident regression. Closing.
Sign in to join this conversation.