@animastor/orchestration 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animastor/orchestration",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Animastor Orchestration — the generation orchestration/runtime contour of the Animastor backend, physically extracted from the host (§32.30): the unified generation lifecycle owner (orchestrator facade, stage executor, scene callbacks/restoration), the dispatch engine and its lease/quota/retry managers, the reconciliation engine and counter reconciliation, the scene window/scheduler/worker-health, the runtime-result emitter/consumer, and the eight O-2..O-10 port contracts (Persistence, SceneData, PlaceholderAudio, ProgressEvents, AudioFsm, VideoFsm, HubCancel, LayerConfig). The package reaches the host (runtime config slices, Redis-domain state layer, media facades, the S-5 seam registry, the artifact root, the PW-2 workspace resolver) ONLY through the composition-root host-bindings seam — no backend/src require, no storage/book/routes/services, no Redis, no PG, no Express inside.",
5
5
  "keywords": [
6
6
  "animastor",
@@ -32,12 +32,12 @@
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",
35
- "url": "git+https://github.com/Animastor/animastor.git",
35
+ "url": "git+https://github.com/Animastor/animastor-backend.git",
36
36
  "directory": "packages/animastor-orchestration"
37
37
  },
38
- "homepage": "https://github.com/Animastor/animastor/tree/main/packages/animastor-orchestration#readme",
38
+ "homepage": "https://github.com/Animastor/animastor-backend/tree/main/packages/animastor-orchestration#readme",
39
39
  "bugs": {
40
- "url": "https://github.com/Animastor/animastor/issues"
40
+ "url": "https://github.com/Animastor/animastor-backend/issues"
41
41
  },
42
42
  "dependencies": {
43
43
  "@animastor/contracts": "^0.1.0",
@@ -607,8 +607,21 @@ async function checkStalledVideoScenes(redis, deps) {
607
607
  // ======================================================
608
608
  // Проверяет соответствие между audio-orch phase и asset state:
609
609
  // phase=DONE ⇔ asset.audio = READY
610
- // phase=FAILED ⇒ asset.audio = FAILED (или PENDING — после re-dispatch)
610
+ // phase=FAILED ⇒ asset.audio ∈ {FAILED, PENDING, DIRTY}
611
611
  // промежуточные ⇒ asset.audio ∈ {PENDING, GENERATING, DIRTY}
612
+ //
613
+ // Stage 47 (FAILED + DIRTY): DIRTY — штатный итог для phase=FAILED.
614
+ // Два писателя приводят к FAILED на стороне оркестратора:
615
+ // • failStage(redispatch=true) → asset = PENDING (FAILED пишется первым и
616
+ // тут же перезаписывается), redispatch=false → asset = FAILED;
617
+ // • startup C1/C1b recovery → setFailed, затем markDirtyScene → asset =
618
+ // DIRTY (+ PG scene_assets.status='stale'). Это сделано нарочно:
619
+ // shouldScheduleAssets() перескакивает READY/FAILED и передиспатчитивает
620
+ // только PENDING/DIRTY, т.е. asset=FAILED застрял бы навсегда, а
621
+ // recommendation 'mark_dirty' (см. ветку ниже) есть ничто иное, как
622
+ // путь к допустимому состоянию. Проверка до stage 47 отвергала именно
623
+ // тот итог, к которому сама же рекомендовала прийти, — ложный
624
+ // audio_orch_invariant_failed на каждой успешной recovery.
612
625
 
613
626
  async function checkAudioOrchInvariants(redis, bookId, chapterId, sceneId) {
614
627
  // O-7: through the AudioFsmPort (host adapter: storage/audio-fsm-adapter)
@@ -637,13 +650,19 @@ async function checkAudioOrchInvariants(redis, bookId, chapterId, sceneId) {
637
650
  });
638
651
  }
639
652
  } else if (phase === PHASES.FAILED) {
640
- if (audioState !== state.AssetState.FAILED && audioState !== state.AssetState.PENDING) {
653
+ // Stage 47: DIRTY is a legitimate FAILED-phase asset state (see the
654
+ // header of this section). Everything else — READY above all — stays
655
+ // a real contradiction: the orchestrator failed while the asset claims
656
+ // its result is accepted.
657
+ if (audioState !== state.AssetState.FAILED &&
658
+ audioState !== state.AssetState.PENDING &&
659
+ audioState !== state.AssetState.DIRTY) {
641
660
  violations.push({
642
661
  type: 'audio_orch_invariant_failed',
643
662
  scene: { bookId, chapterId, sceneId },
644
663
  phase,
645
664
  audioState,
646
- expected: 'FAILED or PENDING',
665
+ expected: 'FAILED, PENDING or DIRTY',
647
666
  recommendation: 'mark_dirty'
648
667
  });
649
668
  }
@@ -668,7 +687,8 @@ async function checkAudioOrchInvariants(redis, bookId, chapterId, sceneId) {
668
687
  // VIDEO-ORCH INVARIANT CHECKS (зеркало checkAudioOrchInvariants)
669
688
  // ======================================================
670
689
  // phase=DONE ⇒ asset.video = READY (или PLACEHOLDER)
671
- // phase=FAILED ⇒ asset.video = FAILED (или PENDING — после re-dispatch)
690
+ // phase=FAILED ⇒ asset.video ∈ {FAILED, PENDING, DIRTY} (stage 47 —
691
+ // зеркало аудио: C1b recovery заканчивается markDirtyScene)
672
692
  // промежуточные ⇒ asset.video = PENDING|GENERATING|DIRTY
673
693
 
674
694
  async function checkVideoOrchInvariants(redis, bookId, chapterId, sceneId) {
@@ -698,13 +718,17 @@ async function checkVideoOrchInvariants(redis, bookId, chapterId, sceneId) {
698
718
  });
699
719
  }
700
720
  } else if (phase === PHASES.FAILED) {
701
- if (videoState !== state.AssetState.FAILED && videoState !== state.AssetState.PENDING) {
721
+ // Stage 47: mirror of the audio branch — DIRTY is the deliberate C1b
722
+ // recovery outcome (markDirtyScene → asset DIRTY for re-dispatch).
723
+ if (videoState !== state.AssetState.FAILED &&
724
+ videoState !== state.AssetState.PENDING &&
725
+ videoState !== state.AssetState.DIRTY) {
702
726
  violations.push({
703
727
  type: 'video_orch_invariant_failed',
704
728
  scene: { bookId, chapterId, sceneId },
705
729
  phase,
706
730
  videoState,
707
- expected: 'FAILED or PENDING',
731
+ expected: 'FAILED, PENDING or DIRTY',
708
732
  recommendation: 'mark_dirty'
709
733
  });
710
734
  }