@rslsp1/fa-app-tools 3.0.0 → 4.0.0

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/dist/szenen.js CHANGED
@@ -40,6 +40,7 @@ __export(szenen_exports, {
40
40
  ELEMENT_VERSION_SCHEMA_FILE: () => ELEMENT_VERSION_SCHEMA_FILE,
41
41
  FLOW_EXECUTION_PATH: () => FLOW_EXECUTION_PATH,
42
42
  PROBE_VERSION_ID: () => PROBE_VERSION_ID,
43
+ PROMPT_RULE_EFFECT: () => PROMPT_RULE_EFFECT,
43
44
  REFERENCE_FIELD: () => REFERENCE_FIELD,
44
45
  RULES_WITHOUT_CAPABILITY_EFFECT: () => RULES_WITHOUT_CAPABILITY_EFFECT,
45
46
  RULE_SCOPES: () => RULE_SCOPES,
@@ -76,6 +77,7 @@ __export(szenen_exports, {
76
77
  checkDraftChainMeta: () => checkDraftChainMeta,
77
78
  checkElementType: () => checkElementType,
78
79
  checkImageExecutionProfile: () => checkImageExecutionProfile,
80
+ checkImageExecutionProfiles: () => checkImageExecutionProfiles,
79
81
  checkImageModelParameters: () => checkImageModelParameters,
80
82
  checkOptionalId: () => checkOptionalId,
81
83
  checkParents: () => checkParents,
@@ -124,7 +126,10 @@ __export(szenen_exports, {
124
126
  derivationPoliciesOf: () => derivationPoliciesOf,
125
127
  deriveItemFromRun: () => deriveItemFromRun,
126
128
  deriveLineage: () => deriveLineage,
129
+ describableContent: () => describableContent,
127
130
  describeTargetModelFailure: () => describeTargetModelFailure,
131
+ diagnosticOfFinding: () => diagnosticOfFinding,
132
+ diagnosticOfSchemaError: () => diagnosticOfSchemaError,
128
133
  differentialSteps: () => differentialSteps,
129
134
  draftRevisionOf: () => draftRevisionOf,
130
135
  elementStoreContractChecks: () => elementStoreContractChecks,
@@ -139,6 +144,7 @@ __export(szenen_exports, {
139
144
  firstError: () => firstError,
140
145
  formatSchemaErrors: () => formatSchemaErrors,
141
146
  freezeDraftChain: () => freezeDraftChain,
147
+ freezeSceneWorkingState: () => freezeSceneWorkingState,
142
148
  getSzenenSchemas: () => getSzenenSchemas,
143
149
  hasPlacementCapability: () => hasPlacementCapability,
144
150
  isKnownElementType: () => isKnownElementType,
@@ -155,22 +161,26 @@ __export(szenen_exports, {
155
161
  parseRunResponse: () => parseRunResponse,
156
162
  preferredHeadRevisionOf: () => preferredHeadRevisionOf,
157
163
  preferredVersionId: () => preferredVersionId,
164
+ promptDiagnosticsOf: () => promptDiagnosticsOf,
158
165
  publishedHeadsOf: () => publishedHeadsOf,
159
166
  recoveriesForRun: () => recoveriesForRun,
160
167
  recoveryStatusOf: () => recoveryStatusOf,
161
168
  reduceElementEvents: () => reduceElementEvents,
162
169
  resolveArea: () => resolveArea,
163
170
  resolvePreferredHead: () => resolvePreferredHead,
171
+ resolveScenePayload: () => resolveScenePayload,
164
172
  resolveShot: () => resolveShot,
165
173
  resolveShotPayload: () => resolveShotPayload,
166
174
  resolveTargetModelOver: () => resolveTargetModelOver,
167
175
  resolverFromQueries: () => resolverFromQueries,
168
176
  roundOfRun: () => roundOfRun,
177
+ rulesWithoutPromptEffect: () => rulesWithoutPromptEffect,
169
178
  runElementStoreContract: () => runElementStoreContract,
170
179
  runPromptDerivation: () => runPromptDerivation,
171
180
  runPublishChecks: () => runPublishChecks,
172
181
  runSceneDerivation: () => runSceneDerivation,
173
182
  runStoreDifferential: () => runStoreDifferential,
183
+ sceneOnlyCapabilities: () => sceneOnlyCapabilities,
174
184
  scopeOfPath: () => scopeOfPath,
175
185
  selectableTargetModels: () => selectableTargetModels,
176
186
  showChain: () => showChain,
@@ -4254,6 +4264,96 @@ function finish(report) {
4254
4264
  };
4255
4265
  }
4256
4266
 
4267
+ // src/lib/szenen/promptOperation.ts
4268
+ var PROMPT_RULE_EFFECT = {
4269
+ "P-01": "diagnostic",
4270
+ // Kamera-ID im Rig nicht auflösbar → ohne Kamera weiter
4271
+ "P-02": "diagnostic",
4272
+ // mehrdeutige Kamera-ID → erklären, nicht sperren
4273
+ "P-03": "diagnostic",
4274
+ // Abstammungsintegrität einer camera_id — Publish-Frage
4275
+ "P-04": "diagnostic",
4276
+ // referenzierte Version nicht veröffentlicht/sichtbar
4277
+ "P-05": "diagnostic",
4278
+ // Node-Referenz nicht auflösbar → Teil auslassen
4279
+ "P-06": "diagnostic",
4280
+ // Placement-Node mehrdeutig → ohne exakte Platzierung
4281
+ "P-07": "diagnostic",
4282
+ // spatial Pattern ohne can_place → Pattern weglassen
4283
+ "P-08": "diagnostic",
4284
+ // unvollständige Pattern-Bindings
4285
+ "P-09": "not_applicable",
4286
+ // reine Publish-/Prozessregel für sequence
4287
+ "P-10": "diagnostic",
4288
+ // Zyklus: Blocker nur, wenn keine endliche Auflösung bleibt
4289
+ "P-11": "diagnostic",
4290
+ // Override-Disziplin, schon bisher advisory
4291
+ "P-12": "not_applicable",
4292
+ // Laufzeitregel der Auflösung, keine Bedingung
4293
+ "P-13": "diagnostic",
4294
+ // pattern_derived ohne Pattern-Platzierung
4295
+ "P-14": "diagnostic",
4296
+ // Bildgrößen-/Optik-Plausibilität, erklärte Absicht gewinnt
4297
+ "P-15": "diagnostic",
4298
+ // vertikaler look_at ohne up_hint — Rollwinkel ist Spezialpräzision
4299
+ "P-16": "diagnostic",
4300
+ // Placements ohne Koordinatensystem
4301
+ "P-17": "diagnostic"
4302
+ // Target Model nicht auflösbar → generischer Prompt
4303
+ };
4304
+ function rulesWithoutPromptEffect(alleRegeln) {
4305
+ return alleRegeln.filter((rule) => !(rule in PROMPT_RULE_EFFECT));
4306
+ }
4307
+ function diagnosticOfFinding(finding) {
4308
+ return {
4309
+ code: finding.rule,
4310
+ origin: "rule",
4311
+ path: finding.path,
4312
+ message: finding.message
4313
+ };
4314
+ }
4315
+ function diagnosticOfSchemaError(error, where) {
4316
+ return {
4317
+ code: "schema",
4318
+ origin: "schema",
4319
+ path: error.instancePath || "/",
4320
+ message: `${where}: ${error.message}`
4321
+ };
4322
+ }
4323
+ function promptDiagnosticsOf(checks) {
4324
+ const befunde = [];
4325
+ for (const finding of checks.findings) {
4326
+ if (PROMPT_RULE_EFFECT[finding.rule] === "not_applicable") continue;
4327
+ befunde.push(diagnosticOfFinding(finding));
4328
+ }
4329
+ return befunde;
4330
+ }
4331
+ var isObject5 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
4332
+ var asArray2 = (v) => Array.isArray(v) ? v : [];
4333
+ var istText = (v) => typeof v === "string" && v.trim().length > 0;
4334
+ function describableContent(scenePayload) {
4335
+ if (!isObject5(scenePayload)) {
4336
+ return {
4337
+ ok: false,
4338
+ message: `Die Szene ist kein Objekt, sondern ${Array.isArray(scenePayload) ? "ein Array" : typeof scenePayload}. Daraus laesst sich kein Textauftrag herstellen.`
4339
+ };
4340
+ }
4341
+ const nodes = asArray2(scenePayload.nodes);
4342
+ for (const node of nodes) {
4343
+ if (!isObject5(node)) continue;
4344
+ const semantic = isObject5(node.semantic) ? node.semantic : null;
4345
+ if (semantic && istText(semantic.description)) return { ok: true };
4346
+ if (asArray2(node.component_refs).length > 0) return { ok: true };
4347
+ }
4348
+ const environment = isObject5(scenePayload.environment) ? scenePayload.environment : null;
4349
+ if (environment && istText(environment.text)) return { ok: true };
4350
+ if (environment && asArray2(environment.component_refs).length > 0) return { ok: true };
4351
+ return {
4352
+ ok: false,
4353
+ message: nodes.length === 0 ? "Die Szene hat keine Knoten und keinen Umgebungstext. Ohne beschreibbaren Inhalt gibt es nichts, woraus ein Prompt entstehen koennte." : `Keiner der ${nodes.length} Knoten traegt eine Beschreibung oder eine Komponentenreferenz, und es gibt keinen Umgebungstext. Ein Prompt daraus waere eine leere Behauptung.`
4354
+ };
4355
+ }
4356
+
4257
4357
  // src/lib/szenen/capabilities.ts
4258
4358
  var CapabilityAnchorError = class extends Error {
4259
4359
  };
@@ -4296,9 +4396,9 @@ var FLAG_OF_SCOPE = {
4296
4396
  // die Vererbung an die beiden anderen weitergereicht.
4297
4397
  global: "can_describe_scene"
4298
4398
  };
4299
- var isObject5 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
4399
+ var isObject6 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
4300
4400
  function nodeCountOf(scenePayload) {
4301
- if (!isObject5(scenePayload)) return 0;
4401
+ if (!isObject6(scenePayload)) return 0;
4302
4402
  return Array.isArray(scenePayload.nodes) ? scenePayload.nodes.length : 0;
4303
4403
  }
4304
4404
  async function capabilityReport(input) {
@@ -4323,7 +4423,7 @@ async function capabilityReport(input) {
4323
4423
  reason: "Payload verletzt das Schema \u2014 die Publish-Regeln wurden nicht ausgefuehrt"
4324
4424
  }))
4325
4425
  } : await runPublishChecks({ type, payload: setupPayload, elementId, parents, resolver });
4326
- if (!isObject5(setupPayload)) {
4426
+ if (!isObject6(setupPayload)) {
4327
4427
  const vorgefunden = Array.isArray(setupPayload) ? "array" : typeof setupPayload;
4328
4428
  const reasons = [
4329
4429
  {
@@ -4333,10 +4433,14 @@ async function capabilityReport(input) {
4333
4433
  ];
4334
4434
  return {
4335
4435
  can_describe_scene: { state: "no", reasons },
4436
+ // Auch fuer den Promptpfad ein echter Blocker: Eine Payload, die kein
4437
+ // Objekt ist, ist technisch unlesbar (Schritt 07, Klasse A/C) — nicht
4438
+ // bloss fachlich unvollstaendig.
4336
4439
  can_render_prompt: { state: "no", reasons },
4337
4440
  can_place: { state: "no", reasons },
4338
4441
  checks,
4339
- schemaErrors
4442
+ schemaErrors,
4443
+ promptDiagnostics: []
4340
4444
  };
4341
4445
  }
4342
4446
  const blockedByScope = /* @__PURE__ */ new Map();
@@ -4372,6 +4476,8 @@ async function capabilityReport(input) {
4372
4476
  };
4373
4477
  const base = forFlag("can_describe_scene");
4374
4478
  let describe;
4479
+ let szenenPayload = null;
4480
+ let sceneVersionId = null;
4375
4481
  if (base.blocked.length > 0) {
4376
4482
  describe = { state: "no", reasons: base.blocked };
4377
4483
  } else if (schemaErrors.length > 0) {
@@ -4397,9 +4503,10 @@ async function capabilityReport(input) {
4397
4503
  ]
4398
4504
  };
4399
4505
  } else {
4400
- const sceneRef = isObject5(setupPayload.scene_ref) ? setupPayload.scene_ref : null;
4401
- const sceneVersionId = typeof sceneRef?.version_id === "string" ? sceneRef.version_id : null;
4506
+ const sceneRef = isObject6(setupPayload.scene_ref) ? setupPayload.scene_ref : null;
4507
+ sceneVersionId = typeof sceneRef?.version_id === "string" ? sceneRef.version_id : null;
4402
4508
  const scene = chainScene !== void 0 ? { payload: chainScene } : sceneVersionId ? await resolver.getVersion(sceneVersionId) : null;
4509
+ if (scene) szenenPayload = { payload: scene.payload };
4403
4510
  const nodes = nodeCountOf(scene?.payload);
4404
4511
  if (nodes === 0) {
4405
4512
  describe = {
@@ -4446,15 +4553,38 @@ async function capabilityReport(input) {
4446
4553
  if (own.unchecked.length > 0) return { state: "unknown", reasons: own.unchecked };
4447
4554
  return { state: "yes", reasons: [] };
4448
4555
  };
4556
+ const promptFlag = (() => {
4557
+ if (!szenenPayload) {
4558
+ return {
4559
+ state: "unknown",
4560
+ reasons: [
4561
+ {
4562
+ kind: "structure",
4563
+ message: `Die Szene ${sceneVersionId ?? "(ohne version_id)"} wurde nicht gelesen; ob beschreibbarer Inhalt vorliegt, ist damit offen \u2014 keine Absage.`
4564
+ }
4565
+ ]
4566
+ };
4567
+ }
4568
+ const inhalt = describableContent(szenenPayload.payload);
4569
+ if (!inhalt.ok) {
4570
+ return { state: "no", reasons: [{ kind: "structure", message: inhalt.message }] };
4571
+ }
4572
+ return { state: "yes", reasons: [] };
4573
+ })();
4574
+ const promptDiagnostics = [
4575
+ ...schemaErrors.map((e) => diagnosticOfSchemaError(e, `Scene Setup ${elementId}`)),
4576
+ ...promptDiagnosticsOf(checks)
4577
+ ];
4449
4578
  return {
4450
4579
  can_describe_scene: describe,
4451
- can_render_prompt: derived("can_render_prompt"),
4580
+ can_render_prompt: promptFlag,
4452
4581
  can_place: derived("can_place", {
4453
4582
  ok: hasPlacementCapability(setupPayload),
4454
4583
  message: "Das Scene Setup traegt kein coordinate_system und ist damit nicht platzierbar (D-65)."
4455
4584
  }),
4456
4585
  checks,
4457
- schemaErrors
4586
+ schemaErrors,
4587
+ promptDiagnostics
4458
4588
  };
4459
4589
  }
4460
4590
  function unclassifiedPublishRules() {
@@ -4462,16 +4592,37 @@ function unclassifiedPublishRules() {
4462
4592
  (rule) => !(rule in RULE_SCOPES) && !(rule in RULES_WITHOUT_CAPABILITY_EFFECT)
4463
4593
  );
4464
4594
  }
4595
+ function sceneOnlyCapabilities(scenePayload) {
4596
+ const knoten = nodeCountOf(scenePayload);
4597
+ const inhalt = describableContent(scenePayload);
4598
+ return {
4599
+ can_describe_scene: knoten > 0 ? { state: "yes", reasons: [] } : {
4600
+ state: "no",
4601
+ reasons: [{
4602
+ kind: "structure",
4603
+ message: "Die Szene hat keine Knoten. Ohne Knoten gibt es nichts zu beschreiben."
4604
+ }]
4605
+ },
4606
+ can_render_prompt: inhalt.ok ? { state: "yes", reasons: [] } : { state: "no", reasons: [{ kind: "structure", message: inhalt.message }] },
4607
+ can_place: {
4608
+ state: "no",
4609
+ reasons: [{
4610
+ kind: "structure",
4611
+ message: "Zu dieser Szene gehoert kein Scene Setup. Weltplatzierung und coordinate_system liegen ausschliesslich dort (D-39/D-65) \u2014 es gibt also keine belastbaren Koordinaten."
4612
+ }]
4613
+ }
4614
+ };
4615
+ }
4465
4616
 
4466
4617
  // src/lib/szenen/resolve.ts
4467
4618
  var ResolveTechnicalError = class extends Error {
4468
4619
  };
4469
- var isObject6 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
4470
- var asArray2 = (v) => Array.isArray(v) ? v : [];
4620
+ var isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
4621
+ var asArray3 = (v) => Array.isArray(v) ? v : [];
4471
4622
  var str = (v) => typeof v === "string" ? v : null;
4472
4623
  var num = (v) => typeof v === "number" ? v : null;
4473
4624
  async function refOf(resolver, ref, expected, path) {
4474
- const versionId = isObject6(ref) ? str(ref.version_id) : null;
4625
+ const versionId = isObject7(ref) ? str(ref.version_id) : null;
4475
4626
  if (!versionId) {
4476
4627
  return {
4477
4628
  ok: false,
@@ -4523,8 +4674,11 @@ async function refOf(resolver, ref, expected, path) {
4523
4674
  }
4524
4675
  return { ok: true, version };
4525
4676
  }
4677
+ function ausgelassen(diagnostics, code, path, message) {
4678
+ diagnostics.push({ code, origin: "resolution", path, message });
4679
+ }
4526
4680
  function entraeumlichtePlatzierung(placement, assumptions) {
4527
- if (!isObject6(placement)) return null;
4681
+ if (!isObject7(placement)) return null;
4528
4682
  if (placement.mode !== "pattern") {
4529
4683
  assumptions.push(
4530
4684
  `Die Kameraplatzierung (mode "${str(placement.mode) ?? "unbekannt"}") ist metrisch und entfaellt ohne can_place. Der Renderer darf daraus keine Position ableiten.`
@@ -4539,7 +4693,7 @@ function entraeumlichtePlatzierung(placement, assumptions) {
4539
4693
  const entfallen = [];
4540
4694
  if (placement.offsets !== void 0) entfallen.push("offsets");
4541
4695
  const height = placement.height;
4542
- if (isObject6(height)) {
4696
+ if (isObject7(height)) {
4543
4697
  if (height.mode === "anchor") {
4544
4698
  const behalteneHoehe = {
4545
4699
  mode: "anchor",
@@ -4618,142 +4772,328 @@ async function resolveShotPayload(input) {
4618
4772
  chain
4619
4773
  } = input;
4620
4774
  const assumptions = [];
4621
- const shotVersion = {
4622
- version_id: shotVersionId,
4623
- element_id: shotElementId,
4624
- payload: shotPayload
4625
- };
4626
- const shotErrors = ohneKettenReferenz(
4627
- validatePayload("shot", shotVersion.payload).errors,
4628
- chain ? "scene_setup_ref" : null
4629
- );
4630
- if (shotErrors.length > 0) {
4775
+ const diagnostics = [];
4776
+ if (!isObject7(shotPayload)) {
4631
4777
  return {
4632
4778
  kind: "rejected",
4633
4779
  failure: {
4634
4780
  class: "schema",
4635
4781
  where: "shot",
4636
- message: `Die Shot-Payload verletzt das Schema (${shotErrors.length} Befunde). Es wurde keine ihrer Referenzen aufgeloest.`,
4637
- errors: shotErrors
4782
+ message: `Die Shot-Payload ist kein Objekt, sondern ${Array.isArray(shotPayload) ? "ein Array" : typeof shotPayload}. Daraus laesst sich kein Auftrag herstellen.`,
4783
+ errors: []
4784
+ }
4785
+ };
4786
+ }
4787
+ const shot = shotPayload;
4788
+ for (const fehler4 of ohneKettenReferenz(
4789
+ validatePayload("shot", shotPayload).errors,
4790
+ chain ? "scene_setup_ref" : null
4791
+ )) {
4792
+ diagnostics.push(diagnosticOfSchemaError(fehler4, `Shot ${shotElementId}`));
4793
+ }
4794
+ let setup = null;
4795
+ let report = null;
4796
+ let canPlace = false;
4797
+ let capabilities;
4798
+ let scene;
4799
+ const nenntSetup = chain !== void 0 || shot.scene_setup_ref !== void 0;
4800
+ if (!nenntSetup) {
4801
+ return {
4802
+ kind: "rejected",
4803
+ failure: {
4804
+ class: "no_content",
4805
+ message: `Der Shot ${shotElementId} nennt kein scene_setup_ref und fuehrt keine Draft-Kette. Ohne Setup gibt es keinen Weg zu einer Szene und damit keinen beschreibbaren Inhalt.`
4638
4806
  }
4639
4807
  };
4640
4808
  }
4641
- const shot = shotVersion.payload;
4642
4809
  const setupRef = chain ? { ok: true, version: chain.setup } : await refOf(resolver, shot.scene_setup_ref, "scene_setup", "/scene_setup_ref");
4643
4810
  if (!setupRef.ok) return { kind: "rejected", failure: setupRef.failure };
4644
- const setupErrors = ohneKettenReferenz(
4645
- validatePayload("scene_setup", setupRef.version.payload).errors,
4646
- chain ? "scene_ref" : null
4647
- );
4648
- if (setupErrors.length > 0) {
4811
+ if (!isObject7(setupRef.version.payload)) {
4649
4812
  return {
4650
4813
  kind: "rejected",
4651
4814
  failure: {
4652
4815
  class: "schema",
4653
4816
  where: "scene_setup",
4654
- message: `Die Scene-Setup-Payload verletzt das Schema (${setupErrors.length} Befunde). Weder ihre Referenzen noch der Faehigkeitsbericht wurden mit einem Resolver gefahren.`,
4655
- errors: setupErrors
4817
+ message: `Die Scene-Setup-Payload ist kein Objekt, sondern ${Array.isArray(setupRef.version.payload) ? "ein Array" : typeof setupRef.version.payload}.`,
4818
+ errors: []
4656
4819
  }
4657
4820
  };
4658
4821
  }
4659
- const setup = setupRef.version.payload;
4660
- const report = await capabilityReport({
4822
+ setup = {
4823
+ element_id: setupRef.version.element_id,
4824
+ version_id: setupRef.version.version_id,
4825
+ payload: setupRef.version.payload
4826
+ };
4827
+ report = await capabilityReport({
4661
4828
  type: "scene_setup",
4662
- setupPayload: setup,
4663
- elementId: setupRef.version.element_id,
4829
+ setupPayload: setup.payload,
4830
+ elementId: setup.element_id,
4664
4831
  resolver,
4665
4832
  // Bei einer Draft-Kette kommt die Szene von hier, nicht aus `scene_ref`
4666
4833
  // (C1). Dasselbe Regelwerk, ein anderer Weg zur selben Szene.
4667
4834
  ...chain ? { chainScene: chain.scene.payload } : {}
4668
4835
  });
4669
- const gate = capabilityGate(report, "can_render_prompt");
4670
- if (gate) return { kind: "rejected", failure: gate };
4671
- const placeGate = capabilityGate(report, "can_place");
4672
- if (placeGate && placeGate.class === "capability_undetermined") {
4673
- return { kind: "rejected", failure: placeGate };
4674
- }
4675
- const canPlace = report.can_place.state === "yes";
4836
+ diagnostics.push(...report.promptDiagnostics);
4837
+ canPlace = report.can_place.state === "yes";
4676
4838
  if (!canPlace) {
4677
4839
  assumptions.push(
4678
- "can_place ist nicht erfuellt \u2014 alle Platzierungen bleiben null. Der Renderer darf daraus keine Koordinaten ableiten (D-47)."
4840
+ `can_place ist "${report.can_place.state}" \u2014 alle Platzierungen bleiben null. Der Renderer darf daraus keine Koordinaten ableiten (D-47).`
4679
4841
  );
4680
4842
  }
4681
- const sceneRef = chain ? { ok: true, version: chain.scene } : await refOf(resolver, setup.scene_ref, "scene", "/scene_ref");
4843
+ capabilities = {
4844
+ can_describe_scene: report.can_describe_scene.state,
4845
+ can_render_prompt: report.can_render_prompt.state,
4846
+ can_place: report.can_place.state
4847
+ };
4848
+ const sceneRef = chain ? { ok: true, version: chain.scene } : await refOf(resolver, setup.payload.scene_ref, "scene", "/scene_ref");
4682
4849
  if (!sceneRef.ok) return { kind: "rejected", failure: sceneRef.failure };
4683
- const scene = sceneRef.version.payload;
4684
- const cameraId = str(shot.camera_id) ?? "";
4685
- const rig = isObject6(setup.camera_rig) ? setup.camera_rig : {};
4686
- const cameras = asArray2(rig.cameras);
4687
- const cameraIndex = cameras.findIndex(
4688
- (camera2) => isObject6(camera2) && camera2.camera_id === cameraId
4689
- );
4690
- if (cameraIndex < 0) {
4850
+ if (!isObject7(sceneRef.version.payload)) {
4691
4851
  return {
4692
4852
  kind: "rejected",
4693
4853
  failure: {
4694
- class: "reference_unresolvable",
4695
- message: `Die aktive camera_id "${cameraId}" kommt im Rig der Scene-Setup-Version ${setupRef.version.version_id} nicht vor (P-01).`,
4696
- versionId: setupRef.version.version_id,
4697
- path: "/camera_id",
4698
- reason: "unknown"
4854
+ class: "schema",
4855
+ where: "scene",
4856
+ message: `Die Szenen-Payload ist kein Objekt, sondern ${Array.isArray(sceneRef.version.payload) ? "ein Array" : typeof sceneRef.version.payload}.`,
4857
+ errors: []
4699
4858
  }
4700
4859
  };
4701
4860
  }
4702
- const camera = cameras[cameraIndex];
4703
- const presetRef = await refOf(
4861
+ scene = {
4862
+ element_id: sceneRef.version.element_id,
4863
+ version_id: sceneRef.version.version_id,
4864
+ payload: sceneRef.version.payload
4865
+ };
4866
+ return komponiere({
4867
+ shot: { element_id: shotElementId, version_id: shotVersionId, payload: shot },
4868
+ setup,
4869
+ scene,
4870
+ report,
4871
+ capabilities,
4872
+ canPlace,
4704
4873
  resolver,
4705
- camera.preset_ref,
4706
- "camera_preset",
4707
- `/camera_rig/cameras/${cameraIndex}/preset_ref`
4708
- );
4709
- if (!presetRef.ok) return { kind: "rejected", failure: presetRef.failure };
4710
- let pattern = null;
4711
- const placementSpec = isObject6(camera.placement) ? camera.placement : null;
4712
- if (placementSpec && isObject6(placementSpec.pattern_ref)) {
4713
- const patternRef = await refOf(
4714
- resolver,
4715
- placementSpec.pattern_ref,
4716
- "camera_pattern",
4717
- `/camera_rig/cameras/${cameraIndex}/placement/pattern_ref`
4874
+ contextChain,
4875
+ userInstruction,
4876
+ assumptions,
4877
+ diagnostics
4878
+ });
4879
+ }
4880
+ async function resolveScenePayload(input) {
4881
+ const {
4882
+ scenePayload,
4883
+ sceneElementId,
4884
+ sceneVersionId = "",
4885
+ resolver,
4886
+ contextChain,
4887
+ userInstruction
4888
+ } = input;
4889
+ if (!isObject7(scenePayload)) {
4890
+ return {
4891
+ kind: "rejected",
4892
+ failure: {
4893
+ class: "schema",
4894
+ where: "scene",
4895
+ message: `Die Szenen-Payload ist kein Objekt, sondern ${Array.isArray(scenePayload) ? "ein Array" : typeof scenePayload}.`,
4896
+ errors: []
4897
+ }
4898
+ };
4899
+ }
4900
+ const assumptions = [
4901
+ "Kein Scene Setup, kein Shot: Der Lauf entsteht aus der Szene allein. Bildaufbau, Kamera und Zielmodell wurden nicht ergaenzt, sondern sind nicht vorhanden (D-135)."
4902
+ ];
4903
+ const diagnostics = [];
4904
+ for (const fehler4 of validatePayload("scene", scenePayload).errors) {
4905
+ diagnostics.push(diagnosticOfSchemaError(fehler4, `Szene ${sceneElementId}`));
4906
+ }
4907
+ const faehig = sceneOnlyCapabilities(scenePayload);
4908
+ return komponiere({
4909
+ shot: null,
4910
+ setup: null,
4911
+ scene: { element_id: sceneElementId, version_id: sceneVersionId, payload: scenePayload },
4912
+ report: null,
4913
+ capabilities: {
4914
+ can_describe_scene: faehig.can_describe_scene.state,
4915
+ can_render_prompt: faehig.can_render_prompt.state,
4916
+ can_place: faehig.can_place.state
4917
+ },
4918
+ canPlace: false,
4919
+ resolver,
4920
+ contextChain,
4921
+ userInstruction,
4922
+ assumptions,
4923
+ diagnostics
4924
+ });
4925
+ }
4926
+ async function komponiere(z) {
4927
+ const {
4928
+ shot,
4929
+ setup,
4930
+ scene,
4931
+ report,
4932
+ capabilities,
4933
+ canPlace,
4934
+ resolver,
4935
+ contextChain,
4936
+ userInstruction,
4937
+ assumptions,
4938
+ diagnostics
4939
+ } = z;
4940
+ const inhalt = describableContent(scene.payload);
4941
+ if (!inhalt.ok) {
4942
+ return {
4943
+ kind: "rejected",
4944
+ failure: {
4945
+ class: "no_content",
4946
+ message: `Szene ${scene.element_id}: ${inhalt.message}`
4947
+ }
4948
+ };
4949
+ }
4950
+ const eingefroreneFaehigkeiten = {
4951
+ ...capabilities,
4952
+ can_render_prompt: "yes"
4953
+ };
4954
+ const shotOverrides = shot && isObject7(shot.payload.overrides) ? shot.payload.overrides : {};
4955
+ const settings = shot && isObject7(shot.payload.prompt_render_settings) ? shot.payload.prompt_render_settings : {};
4956
+ let camera = null;
4957
+ if (shot && setup) {
4958
+ const cameraId = str(shot.payload.camera_id);
4959
+ const rig = isObject7(setup.payload.camera_rig) ? setup.payload.camera_rig : {};
4960
+ const cameras = asArray3(rig.cameras);
4961
+ const cameraIndex = cameraId === null ? -1 : cameras.findIndex((c) => isObject7(c) && c.camera_id === cameraId);
4962
+ if (cameraId === null) {
4963
+ ausgelassen(
4964
+ diagnostics,
4965
+ "P-01",
4966
+ "/camera_id",
4967
+ `Der Shot ${shot.element_id} nennt keine camera_id. Der Prompt entsteht ohne Kameravorgabe; eine Kamera wird nicht erfunden (D-75).`
4968
+ );
4969
+ } else if (cameraIndex < 0) {
4970
+ ausgelassen(
4971
+ diagnostics,
4972
+ "P-01",
4973
+ "/camera_id",
4974
+ `Die aktive camera_id "${cameraId}" kommt im Rig der Scene-Setup-Version ${setup.version_id} nicht vor. Der Prompt entsteht ohne Kameravorgabe.`
4975
+ );
4976
+ } else {
4977
+ const rohKamera = cameras[cameraIndex];
4978
+ let preset = null;
4979
+ const presetRef = await refOf(
4980
+ resolver,
4981
+ rohKamera.preset_ref,
4982
+ "camera_preset",
4983
+ `/camera_rig/cameras/${cameraIndex}/preset_ref`
4984
+ );
4985
+ if (presetRef.ok) preset = presetRef.version.payload;
4986
+ else {
4987
+ ausgelassen(
4988
+ diagnostics,
4989
+ "P-04",
4990
+ `/camera_rig/cameras/${cameraIndex}/preset_ref`,
4991
+ `${presetRef.failure.message} Die Kamera geht ohne Preset in den Prompt.`
4992
+ );
4993
+ }
4994
+ let pattern = null;
4995
+ const placementSpec = isObject7(rohKamera.placement) ? rohKamera.placement : null;
4996
+ if (placementSpec && isObject7(placementSpec.pattern_ref)) {
4997
+ const patternRef = await refOf(
4998
+ resolver,
4999
+ placementSpec.pattern_ref,
5000
+ "camera_pattern",
5001
+ `/camera_rig/cameras/${cameraIndex}/placement/pattern_ref`
5002
+ );
5003
+ if (patternRef.ok) pattern = patternRef.version.payload;
5004
+ else {
5005
+ ausgelassen(
5006
+ diagnostics,
5007
+ "P-04",
5008
+ `/camera_rig/cameras/${cameraIndex}/placement/pattern_ref`,
5009
+ `${patternRef.failure.message} Das Kameramuster entfaellt im Prompt.`
5010
+ );
5011
+ }
5012
+ }
5013
+ const cameraPlacement = canPlace ? rohKamera.placement ?? null : entraeumlichtePlatzierung(rohKamera.placement, assumptions);
5014
+ camera = {
5015
+ camera_id: cameraId,
5016
+ name: str(rohKamera.name),
5017
+ preset,
5018
+ placement: cameraPlacement,
5019
+ orientation: rohKamera.orientation ?? null,
5020
+ // Der Shot darf Bildgroesse und Fokus ueberschreiben (D-40) — das ist
5021
+ // die oberste Stufe der Vorrangkette.
5022
+ framing: shotOverrides.framing ?? rohKamera.framing ?? null,
5023
+ focus: shotOverrides.focus !== void 0 ? shotOverrides.focus : rohKamera.focus ?? null,
5024
+ pattern
5025
+ };
5026
+ }
5027
+ } else if (shot && !setup) {
5028
+ ausgelassen(
5029
+ diagnostics,
5030
+ "P-01",
5031
+ "/camera_id",
5032
+ "Ohne Scene Setup gibt es kein Camera Rig. Der Prompt entsteht ohne Kameravorgabe."
4718
5033
  );
4719
- if (!patternRef.ok) return { kind: "rejected", failure: patternRef.failure };
4720
- pattern = patternRef.version.payload;
4721
5034
  }
4722
5035
  let shotConcept = null;
4723
- if (isObject6(shot.shot_concept_ref)) {
5036
+ if (shot && isObject7(shot.payload.shot_concept_ref)) {
4724
5037
  const conceptRef = await refOf(
4725
5038
  resolver,
4726
- shot.shot_concept_ref,
5039
+ shot.payload.shot_concept_ref,
4727
5040
  "shot_concept",
4728
5041
  "/shot_concept_ref"
4729
5042
  );
4730
- if (!conceptRef.ok) return { kind: "rejected", failure: conceptRef.failure };
4731
- shotConcept = conceptRef.version.payload;
5043
+ if (conceptRef.ok) shotConcept = conceptRef.version.payload;
5044
+ else {
5045
+ ausgelassen(
5046
+ diagnostics,
5047
+ "P-04",
5048
+ "/shot_concept_ref",
5049
+ `${conceptRef.failure.message} Das Shot Concept entfaellt im Prompt.`
5050
+ );
5051
+ }
4732
5052
  }
4733
5053
  const styles = [];
4734
5054
  for (const [ebene, refs] of [
4735
- ["scene_setup", asArray2(setup.style_refs)],
4736
- ["shot", asArray2(shot.style_refs)]
5055
+ ["scene_setup", setup ? asArray3(setup.payload.style_refs) : []],
5056
+ ["shot", shot ? asArray3(shot.payload.style_refs) : []]
4737
5057
  ]) {
4738
5058
  for (const [i, ref] of refs.entries()) {
4739
5059
  const resolved = await refOf(resolver, ref, "style", `/${ebene}/style_refs/${i}`);
4740
- if (!resolved.ok) return { kind: "rejected", failure: resolved.failure };
5060
+ if (!resolved.ok) {
5061
+ ausgelassen(
5062
+ diagnostics,
5063
+ "P-04",
5064
+ `/${ebene}/style_refs/${i}`,
5065
+ `${resolved.failure.message} Dieser Stil entfaellt im Prompt.`
5066
+ );
5067
+ continue;
5068
+ }
4741
5069
  const payload = resolved.version.payload;
4742
5070
  styles.push({
4743
- role: str(isObject6(ref) ? ref.role : null) ?? str(payload.role) ?? "unspecified",
4744
- rank: num(isObject6(ref) ? ref.rank : null) ?? 0,
4745
- weight: num(isObject6(ref) ? ref.weight : null),
5071
+ role: str(isObject7(ref) ? ref.role : null) ?? str(payload.role) ?? "unspecified",
5072
+ rank: num(isObject7(ref) ? ref.rank : null) ?? 0,
5073
+ weight: num(isObject7(ref) ? ref.weight : null),
4746
5074
  text: str(payload.text) ?? "",
4747
5075
  locale: str(payload.locale)
4748
5076
  });
4749
5077
  }
4750
5078
  }
4751
5079
  styles.sort((a, b) => a.rank - b.rank);
4752
- const settings = isObject6(shot.prompt_render_settings) ? shot.prompt_render_settings : {};
4753
5080
  const policies = [];
4754
- for (const [i, ref] of asArray2(settings.policy_refs).entries()) {
4755
- const resolved = await refOf(resolver, ref, "prompt_policy", `/prompt_render_settings/policy_refs/${i}`);
4756
- if (!resolved.ok) return { kind: "rejected", failure: resolved.failure };
5081
+ for (const [i, ref] of asArray3(settings.policy_refs).entries()) {
5082
+ const resolved = await refOf(
5083
+ resolver,
5084
+ ref,
5085
+ "prompt_policy",
5086
+ `/prompt_render_settings/policy_refs/${i}`
5087
+ );
5088
+ if (!resolved.ok) {
5089
+ ausgelassen(
5090
+ diagnostics,
5091
+ "P-04",
5092
+ `/prompt_render_settings/policy_refs/${i}`,
5093
+ `${resolved.failure.message} Diese Policy entfaellt im Prompt.`
5094
+ );
5095
+ continue;
5096
+ }
4757
5097
  const payload = resolved.version.payload;
4758
5098
  policies.push({
4759
5099
  subtype: str(payload.subtype) ?? "general",
@@ -4764,14 +5104,22 @@ async function resolveShotPayload(input) {
4764
5104
  }
4765
5105
  policies.sort((a, b) => a.rank - b.rank);
4766
5106
  const fragments = [];
4767
- for (const [i, ref] of asArray2(settings.fragment_refs).entries()) {
5107
+ for (const [i, ref] of asArray3(settings.fragment_refs).entries()) {
4768
5108
  const resolved = await refOf(
4769
5109
  resolver,
4770
5110
  ref,
4771
5111
  "prompt_fragment",
4772
5112
  `/prompt_render_settings/fragment_refs/${i}`
4773
5113
  );
4774
- if (!resolved.ok) return { kind: "rejected", failure: resolved.failure };
5114
+ if (!resolved.ok) {
5115
+ ausgelassen(
5116
+ diagnostics,
5117
+ "P-04",
5118
+ `/prompt_render_settings/fragment_refs/${i}`,
5119
+ `${resolved.failure.message} Dieses Fragment entfaellt im Prompt.`
5120
+ );
5121
+ continue;
5122
+ }
4775
5123
  const payload = resolved.version.payload;
4776
5124
  fragments.push({
4777
5125
  channel: str(payload.channel) ?? "positive",
@@ -4781,83 +5129,102 @@ async function resolveShotPayload(input) {
4781
5129
  });
4782
5130
  }
4783
5131
  fragments.sort((a, b) => a.rank - b.rank);
4784
- const key = str(settings.target_model_id);
4785
- if (!key) {
4786
- return {
4787
- kind: "rejected",
4788
- failure: {
4789
- class: "target_model_unresolvable",
4790
- message: "Der Shot nennt kein target_model_id.",
4791
- resolution: { kind: "not_found", key: "", chain: contextChain }
4792
- }
4793
- };
4794
- }
4795
- if (!resolver.resolveTargetModel) {
5132
+ let targetModelPayload = null;
5133
+ let targetModelResolution = null;
5134
+ const key = shot ? str(settings.target_model_id) : null;
5135
+ if (key === null) {
5136
+ ausgelassen(
5137
+ diagnostics,
5138
+ "P-17",
5139
+ "/prompt_render_settings/target_model_id",
5140
+ shot ? `Der Shot ${shot.element_id} nennt kein target_model_id. Der Prompt wird generisch abgeleitet, ohne Modelloptimierung.` : "Ohne Shot gibt es kein target_model_id. Der Prompt wird generisch abgeleitet, ohne Modelloptimierung."
5141
+ );
5142
+ } else if (!resolver.resolveTargetModel) {
4796
5143
  throw new ResolveTechnicalError(
4797
5144
  `Der Resolver bietet keine Zielmodellsuche an (kein ContextChainPort). Ein Lauf ohne Kontextkette wuerde ein Zielmodell melden, das nicht das gesuchte ist.`
4798
5145
  );
4799
- }
4800
- const targetModel = await resolver.resolveTargetModel(key, shotVersion.element_id);
4801
- if (targetModel.kind !== "resolved") {
4802
- return {
4803
- kind: "rejected",
4804
- failure: {
4805
- class: "target_model_unresolvable",
4806
- message: describeTargetModelFailure(targetModel),
4807
- resolution: targetModel
5146
+ } else {
5147
+ const targetModel = await resolver.resolveTargetModel(key, shot.element_id);
5148
+ if (targetModel.kind !== "resolved") {
5149
+ ausgelassen(
5150
+ diagnostics,
5151
+ "P-17",
5152
+ "/prompt_render_settings/target_model_id",
5153
+ `${describeTargetModelFailure(targetModel)} Der Prompt wird generisch abgeleitet, ohne Modelloptimierung.`
5154
+ );
5155
+ } else {
5156
+ targetModelPayload = targetModel.payload;
5157
+ targetModelResolution = {
5158
+ element_id: targetModel.elementId,
5159
+ version_id: targetModel.versionId,
5160
+ chain_index: targetModel.chainIndex,
5161
+ head: targetModel.head,
5162
+ shadowed_retired: targetModel.shadowedRetired.map((entry) => ({
5163
+ element_id: entry.elementId,
5164
+ context_id: entry.contextId
5165
+ }))
5166
+ };
5167
+ for (const uebergangen of targetModel.shadowedRetired) {
5168
+ assumptions.push(
5169
+ `Ein stillgelegtes target_model (${uebergangen.elementId}, Kontext ${uebergangen.contextId ?? "global"}) wurde uebergangen; verwendet wird ${targetModel.elementId} von Kettenglied ${targetModel.chainIndex}.`
5170
+ );
4808
5171
  }
4809
- };
4810
- }
4811
- for (const uebergangen of targetModel.shadowedRetired) {
4812
- assumptions.push(
4813
- `Ein stillgelegtes target_model (${uebergangen.elementId}, Kontext ${uebergangen.contextId ?? "global"}) wurde uebergangen; verwendet wird ${targetModel.elementId} von Kettenglied ${targetModel.chainIndex}.`
4814
- );
4815
- }
4816
- if (targetModel.head.kind === "selected" && targetModel.head.stale) {
4817
- assumptions.push(
4818
- `Die Auswahl des Zielmodell-Heads (${targetModel.versionId}) ist veraltet \u2014 es gibt neuere Heads. Die Auswahl gilt, weil sie getroffen wurde (D-36).`
4819
- );
5172
+ if (targetModel.head.kind === "selected" && targetModel.head.stale) {
5173
+ assumptions.push(
5174
+ `Die Auswahl des Zielmodell-Heads (${targetModel.versionId}) ist veraltet \u2014 es gibt neuere Heads. Die Auswahl gilt, weil sie getroffen wurde (D-36).`
5175
+ );
5176
+ }
5177
+ }
4820
5178
  }
4821
5179
  const overrides = /* @__PURE__ */ new Map();
4822
- for (const entry of asArray2(setup.node_overrides)) {
4823
- if (isObject6(entry) && typeof entry.node_id === "string") overrides.set(entry.node_id, entry);
5180
+ for (const entry of setup ? asArray3(setup.payload.node_overrides) : []) {
5181
+ if (isObject7(entry) && typeof entry.node_id === "string") overrides.set(entry.node_id, entry);
4824
5182
  }
4825
5183
  const placements = /* @__PURE__ */ new Map();
4826
- for (const entry of asArray2(setup.placements)) {
4827
- if (!isObject6(entry) || typeof entry.node_id !== "string") continue;
5184
+ for (const entry of setup ? asArray3(setup.payload.placements) : []) {
5185
+ if (!isObject7(entry) || typeof entry.node_id !== "string") continue;
4828
5186
  placements.set(entry.node_id, {
4829
- position: asArray2(entry.position),
4830
- ...entry.rotation_euler_deg ? { rotation_euler_deg: asArray2(entry.rotation_euler_deg) } : {},
4831
- ...entry.scale ? { scale: asArray2(entry.scale) } : {}
5187
+ position: asArray3(entry.position),
5188
+ ...entry.rotation_euler_deg ? { rotation_euler_deg: asArray3(entry.rotation_euler_deg) } : {},
5189
+ ...entry.scale ? { scale: asArray3(entry.scale) } : {}
4832
5190
  });
4833
5191
  }
4834
- const shotOverrides = isObject6(shot.overrides) ? shot.overrides : {};
4835
- const hidden = new Set(asArray2(shotOverrides.hidden_nodes).filter((v) => typeof v === "string"));
5192
+ const hidden = new Set(
5193
+ asArray3(shotOverrides.hidden_nodes).filter((v) => typeof v === "string")
5194
+ );
4836
5195
  const nodes = [];
4837
- for (const raw of asArray2(scene.nodes)) {
4838
- if (!isObject6(raw) || typeof raw.node_id !== "string") continue;
5196
+ for (const raw of asArray3(scene.payload.nodes)) {
5197
+ if (!isObject7(raw) || typeof raw.node_id !== "string") continue;
4839
5198
  const nodeId = raw.node_id;
4840
5199
  const contributions = [];
4841
- for (const [i, ref] of asArray2(raw.component_refs).entries()) {
5200
+ for (const [i, ref] of asArray3(raw.component_refs).entries()) {
4842
5201
  const resolved = await refOf(
4843
5202
  resolver,
4844
5203
  ref,
4845
5204
  "scene_component",
4846
5205
  `/nodes/${nodeId}/component_refs/${i}`
4847
5206
  );
4848
- if (!resolved.ok) return { kind: "rejected", failure: resolved.failure };
5207
+ if (!resolved.ok) {
5208
+ ausgelassen(
5209
+ diagnostics,
5210
+ "P-05",
5211
+ `/nodes/${nodeId}/component_refs/${i}`,
5212
+ `${resolved.failure.message} Dieser Beitrag entfaellt; der Knoten bleibt mit seinen uebrigen Beitraegen im Prompt.`
5213
+ );
5214
+ continue;
5215
+ }
4849
5216
  const payload = resolved.version.payload;
4850
5217
  contributions.push({
4851
5218
  source: "component",
4852
5219
  element_id: resolved.version.element_id,
4853
5220
  version_id: resolved.version.version_id,
4854
- role: str(isObject6(ref) ? ref.role : null),
4855
- rank: num(isObject6(ref) ? ref.rank : null) ?? 0,
5221
+ role: str(isObject7(ref) ? ref.role : null),
5222
+ rank: num(isObject7(ref) ? ref.rank : null) ?? 0,
4856
5223
  locale: str(payload.locale),
4857
5224
  text: str(payload.text) ?? ""
4858
5225
  });
4859
5226
  }
4860
- const semantic = isObject6(raw.semantic) ? raw.semantic : null;
5227
+ const semantic = isObject7(raw.semantic) ? raw.semantic : null;
4861
5228
  if (semantic && str(semantic.description)) {
4862
5229
  contributions.push({
4863
5230
  source: "node_semantic",
@@ -4871,12 +5238,12 @@ async function resolveShotPayload(input) {
4871
5238
  });
4872
5239
  }
4873
5240
  const override = overrides.get(nodeId);
4874
- const overrideSemantic = override && isObject6(override.semantic) ? override.semantic : null;
4875
- if (overrideSemantic && str(overrideSemantic.description)) {
5241
+ const overrideSemantic = override && isObject7(override.semantic) ? override.semantic : null;
5242
+ if (overrideSemantic && str(overrideSemantic.description) && setup) {
4876
5243
  contributions.push({
4877
5244
  source: "setup_override",
4878
- element_id: setupRef.version.element_id,
4879
- version_id: setupRef.version.version_id,
5245
+ element_id: setup.element_id,
5246
+ version_id: setup.version_id,
4880
5247
  role: null,
4881
5248
  rank: Number.MAX_SAFE_INTEGER,
4882
5249
  locale: null,
@@ -4885,8 +5252,8 @@ async function resolveShotPayload(input) {
4885
5252
  }
4886
5253
  contributions.sort((a, b) => a.rank - b.rank);
4887
5254
  const properties = {
4888
- ...isObject6(semantic?.properties) ? semantic.properties : {},
4889
- ...isObject6(overrideSemantic?.properties) ? overrideSemantic.properties : {}
5255
+ ...isObject7(semantic?.properties) ? semantic.properties : {},
5256
+ ...isObject7(overrideSemantic?.properties) ? overrideSemantic.properties : {}
4890
5257
  };
4891
5258
  nodes.push({
4892
5259
  node_id: nodeId,
@@ -4897,9 +5264,6 @@ async function resolveShotPayload(input) {
4897
5264
  hidden: hidden.has(nodeId)
4898
5265
  });
4899
5266
  }
4900
- const cameraPlacement = canPlace ? camera.placement ?? null : entraeumlichtePlatzierung(camera.placement, assumptions);
4901
- const framing = shotOverrides.framing ?? camera.framing;
4902
- const focus = shotOverrides.focus !== void 0 ? shotOverrides.focus : camera.focus ?? null;
4903
5267
  const shotInstruction = str(settings.user_instruction);
4904
5268
  if (userInstruction && shotInstruction && userInstruction !== shotInstruction) {
4905
5269
  assumptions.push(
@@ -4913,56 +5277,37 @@ async function resolveShotPayload(input) {
4913
5277
  kind: "resolved",
4914
5278
  report,
4915
5279
  input: {
4916
- shot: {
4917
- version_id: shotVersion.version_id,
4918
- element_id: shotVersion.element_id,
4919
- camera_id: cameraId,
5280
+ shot: shot ? {
5281
+ version_id: shot.version_id,
5282
+ element_id: shot.element_id,
5283
+ camera_id: camera ? camera.camera_id : null,
4920
5284
  shot_concept: shotConcept,
4921
5285
  // Der Aufrufer darf die im Shot hinterlegte Anweisung ueberschreiben
4922
5286
  // (§4.1). Beide Herkuenfte sind unterschiedliche Sachverhalte, deshalb
4923
5287
  // wird der Fall in `assumptions` benannt statt still ersetzt.
4924
- user_instruction: userInstruction ?? str(settings.user_instruction),
5288
+ user_instruction: userInstruction ?? shotInstruction,
4925
5289
  text_override: str(shotOverrides.text)
4926
- },
5290
+ } : null,
5291
+ setup: setup ? { version_id: setup.version_id, element_id: setup.element_id } : null,
4927
5292
  scene: {
4928
- version_id: sceneRef.version.version_id,
5293
+ element_id: scene.element_id,
5294
+ version_id: scene.version_id,
4929
5295
  nodes,
4930
- relations: asArray2(scene.relations),
4931
- environment: scene.environment ?? null,
4932
- unit_system: scene.unit_system ?? null
4933
- },
4934
- camera: {
4935
- camera_id: cameraId,
4936
- name: str(camera.name),
4937
- preset: presetRef.version.payload,
4938
- placement: cameraPlacement,
4939
- orientation: camera.orientation ?? null,
4940
- framing: framing ?? null,
4941
- focus,
4942
- pattern
5296
+ relations: asArray3(scene.payload.relations),
5297
+ environment: scene.payload.environment ?? null,
5298
+ unit_system: scene.payload.unit_system ?? null
4943
5299
  },
5300
+ camera,
4944
5301
  styles,
4945
5302
  policies,
4946
5303
  fragments,
4947
- target_model: targetModel.payload,
5304
+ target_model: targetModelPayload,
4948
5305
  localization_notes: [],
4949
5306
  assumptions,
4950
- capabilities: {
4951
- can_describe_scene: report.can_describe_scene.state,
4952
- can_render_prompt: report.can_render_prompt.state,
4953
- can_place: report.can_place.state
4954
- },
5307
+ diagnostics,
5308
+ capabilities: eingefroreneFaehigkeiten,
4955
5309
  context_chain: [...contextChain],
4956
- target_model_resolution: {
4957
- element_id: targetModel.elementId,
4958
- version_id: targetModel.versionId,
4959
- chain_index: targetModel.chainIndex,
4960
- head: targetModel.head,
4961
- shadowed_retired: targetModel.shadowedRetired.map((entry) => ({
4962
- element_id: entry.elementId,
4963
- context_id: entry.contextId
4964
- }))
4965
- }
5310
+ target_model_resolution: targetModelResolution
4966
5311
  }
4967
5312
  };
4968
5313
  }
@@ -5105,6 +5450,7 @@ function createFlowTextGenerationPort(generateText, options = {}) {
5105
5450
 
5106
5451
  // src/lib/szenen/promptRun.ts
5107
5452
  function buildSystemInstruction(input) {
5453
+ const ohneZielmodell = input.target_model === null || input.target_model === void 0;
5108
5454
  const model = input.target_model ?? {};
5109
5455
  const sprache = typeof model.prompt_language === "string" ? model.prompt_language : "en";
5110
5456
  const negativ = model.supports_negative_prompt === true;
@@ -5125,7 +5471,11 @@ function buildSystemInstruction(input) {
5125
5471
  "",
5126
5472
  `Der Prompt wird in der Sprache "${sprache}" formuliert.`
5127
5473
  ];
5128
- if (!negativ) {
5474
+ if (ohneZielmodell) {
5475
+ zeilen.push(
5476
+ 'Es ist KEIN Zielmodell angegeben. Formuliere einen generischen Prompt und richte ihn nicht an einer bestimmten Bildmodell-Syntax aus. "negative" bleibt null, weil kein Modell zugesagt hat, ein Negativfeld zu fuehren; was mit negativen Fragmenten geschehen ist, gehoert in "notes".'
5477
+ );
5478
+ } else if (!negativ) {
5129
5479
  zeilen.push(
5130
5480
  'Das Zielmodell kennt KEIN Negativ-Prompt-Feld. "negative" bleibt null; was mit negativen Fragmenten geschehen ist, gehoert in "notes".'
5131
5481
  );
@@ -5154,6 +5504,14 @@ function buildSystemInstruction(input) {
5154
5504
  'Widersprechen sie einander, nenne den Widerspruch mit beiden Quellen in "notes" \u2014',
5155
5505
  "waehle nicht still eine Seite."
5156
5506
  );
5507
+ if (input.camera === null) {
5508
+ zeilen.push(
5509
+ "",
5510
+ "Es ist KEINE Kamera angegeben. Erfinde keine Brennweite, keinen Bildausschnitt",
5511
+ "und keine Kameraposition. Wo eine Kameraaussage noetig waere, formuliere sie",
5512
+ 'als Annahme und nenne sie in "notes".'
5513
+ );
5514
+ }
5157
5515
  if (input.capabilities.can_place !== "yes") {
5158
5516
  zeilen.push(
5159
5517
  "",
@@ -5167,7 +5525,7 @@ function buildSystemInstruction(input) {
5167
5525
  function buildUserPrompt(input) {
5168
5526
  return JSON.stringify(input, null, 2);
5169
5527
  }
5170
- var isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
5528
+ var isObject8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
5171
5529
  function parseRunResponse(raw) {
5172
5530
  const text = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "").trim();
5173
5531
  if (text.length === 0) return { ok: false, message: "Die Antwort war leer." };
@@ -5181,7 +5539,7 @@ function parseRunResponse(raw) {
5181
5539
  }
5182
5540
  }
5183
5541
  function checkRunResponse(value, input) {
5184
- if (!isObject7(value)) {
5542
+ if (!isObject8(value)) {
5185
5543
  return { ok: false, message: `Die Antwort ist kein Objekt, sondern ${Array.isArray(value) ? "array" : typeof value}.` };
5186
5544
  }
5187
5545
  if (typeof value.positive !== "string" || value.positive.trim().length === 0) {
@@ -5199,11 +5557,11 @@ function checkRunResponse(value, input) {
5199
5557
  if (negative !== null && !negativErlaubt) {
5200
5558
  return {
5201
5559
  ok: false,
5202
- message: `Das Zielmodell fuehrt kein Negativ-Prompt-Feld (supports_negative_prompt = false), die Antwort liefert aber eines.`
5560
+ message: input.target_model ? `Das Zielmodell fuehrt kein Negativ-Prompt-Feld (supports_negative_prompt = false), die Antwort liefert aber eines.` : `Dieser Lauf hat kein Zielmodell (generische Ableitung); ein Negativ-Prompt-Feld ist damit nicht zugesagt, die Antwort liefert aber eines.`
5203
5561
  };
5204
5562
  }
5205
5563
  const visibility = value.visibility;
5206
- if (!isObject7(visibility)) {
5564
+ if (!isObject8(visibility)) {
5207
5565
  return { ok: false, message: '"visibility" fehlt \u2014 die Pflichtdiagnosen aus D-21.' };
5208
5566
  }
5209
5567
  if (typeof visibility.basis !== "string") {
@@ -5215,7 +5573,7 @@ function checkRunResponse(value, input) {
5215
5573
  const genannt = /* @__PURE__ */ new Set();
5216
5574
  const nodes = [];
5217
5575
  for (const eintrag of visibility.nodes) {
5218
- if (!isObject7(eintrag) || typeof eintrag.node_id !== "string" || typeof eintrag.state !== "string") {
5576
+ if (!isObject8(eintrag) || typeof eintrag.node_id !== "string" || typeof eintrag.state !== "string") {
5219
5577
  return { ok: false, message: 'Ein Eintrag in "visibility.nodes" hat keine node_id oder keinen state.' };
5220
5578
  }
5221
5579
  genannt.add(eintrag.node_id);
@@ -6109,7 +6467,7 @@ function validateDerivationInput(input) {
6109
6467
  if (input.policy.produces.length === 0) return "Die Regel erzeugt keinen einzigen Vorschlag.";
6110
6468
  return null;
6111
6469
  }
6112
- var isObject8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
6470
+ var isObject9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
6113
6471
  var MAX_PROPOSAL_TITLE_LENGTH = 120;
6114
6472
  function fallbackProposalTitle(type) {
6115
6473
  return `Rekonstruktion ${type}`;
@@ -6135,7 +6493,7 @@ function resolveJsonPointer(wurzel, pointer) {
6135
6493
  aktuell = aktuell[index];
6136
6494
  continue;
6137
6495
  }
6138
- if (!isObject8(aktuell) || !(schluessel in aktuell)) {
6496
+ if (!isObject9(aktuell) || !(schluessel in aktuell)) {
6139
6497
  return { found: false, value: void 0 };
6140
6498
  }
6141
6499
  aktuell = aktuell[schluessel];
@@ -6149,7 +6507,7 @@ function collectVersionRefs2(value) {
6149
6507
  knoten.forEach(besuchen);
6150
6508
  return;
6151
6509
  }
6152
- if (!isObject8(knoten)) return;
6510
+ if (!isObject9(knoten)) return;
6153
6511
  if (typeof knoten.element_id === "string" && typeof knoten.version_id === "string") {
6154
6512
  gefunden.push({ element_id: knoten.element_id, version_id: knoten.version_id });
6155
6513
  }
@@ -6215,7 +6573,7 @@ function assessDerivationResponse(value, input) {
6215
6573
  envelope: null,
6216
6574
  contract_ok: false
6217
6575
  });
6218
- if (!isObject8(value)) {
6576
+ if (!isObject9(value)) {
6219
6577
  befund({
6220
6578
  code: "response.not_object",
6221
6579
  severity: "error",
@@ -6233,7 +6591,7 @@ function assessDerivationResponse(value, input) {
6233
6591
  });
6234
6592
  }
6235
6593
  const rohProposals = value.proposals;
6236
- const proposalsLesbar = isObject8(rohProposals);
6594
+ const proposalsLesbar = isObject9(rohProposals);
6237
6595
  if (!proposalsLesbar) {
6238
6596
  befund({
6239
6597
  code: "envelope.proposals_missing",
@@ -6243,7 +6601,7 @@ function assessDerivationResponse(value, input) {
6243
6601
  });
6244
6602
  }
6245
6603
  const roh = proposalsLesbar ? rohProposals : {};
6246
- const rohGaps = isObject8(value.gaps) ? value.gaps : {};
6604
+ const rohGaps = isObject9(value.gaps) ? value.gaps : {};
6247
6605
  const gapsUngefragt = Object.keys(rohGaps).filter(
6248
6606
  (t) => !input.policy.produces.includes(t)
6249
6607
  );
@@ -6255,7 +6613,7 @@ function assessDerivationResponse(value, input) {
6255
6613
  pointer: "/gaps"
6256
6614
  });
6257
6615
  }
6258
- const fehlend = input.policy.produces.filter((t) => !isObject8(roh[t]));
6616
+ const fehlend = input.policy.produces.filter((t) => !isObject9(roh[t]));
6259
6617
  if (fehlend.length > 0 && proposalsLesbar) {
6260
6618
  const d = befund({
6261
6619
  code: "envelope.proposals_missing_types",
@@ -6276,10 +6634,10 @@ function assessDerivationResponse(value, input) {
6276
6634
  pointer: "/proposals"
6277
6635
  });
6278
6636
  }
6279
- const rohTitles = isObject8(value.titles) ? value.titles : {};
6637
+ const rohTitles = isObject9(value.titles) ? value.titles : {};
6280
6638
  const umgebucht = [];
6281
6639
  for (const type of input.policy.produces) {
6282
- if (!isObject8(roh[type])) continue;
6640
+ if (!isObject9(roh[type])) continue;
6283
6641
  const payload = roh[type];
6284
6642
  const eigene = [];
6285
6643
  const bezug = REFERENCE_FIELD[type];
@@ -6315,7 +6673,7 @@ function assessDerivationResponse(value, input) {
6315
6673
  const bezugPointer = bezug ? `/${bezug.field}` : null;
6316
6674
  let gapFehler = false;
6317
6675
  for (const eintrag of benannt) {
6318
- if (!isObject8(eintrag) || typeof eintrag.pointer !== "string" || typeof eintrag.reason !== "string" || !eintrag.reason.trim()) {
6676
+ if (!isObject9(eintrag) || typeof eintrag.pointer !== "string" || typeof eintrag.reason !== "string" || !eintrag.reason.trim()) {
6319
6677
  eigene.push(befund({
6320
6678
  code: "proposal.gap_entry_invalid",
6321
6679
  severity: "error",
@@ -6391,7 +6749,7 @@ function assessDerivationResponse(value, input) {
6391
6749
  });
6392
6750
  } else {
6393
6751
  for (const eintrag of value.not_derivable) {
6394
- if (!isObject8(eintrag) || typeof eintrag.field !== "string" || typeof eintrag.reason !== "string") {
6752
+ if (!isObject9(eintrag) || typeof eintrag.field !== "string" || typeof eintrag.reason !== "string") {
6395
6753
  befund({
6396
6754
  code: "envelope.not_derivable_entry_invalid",
6397
6755
  severity: "error",
@@ -6416,7 +6774,7 @@ function assessDerivationResponse(value, input) {
6416
6774
  });
6417
6775
  } else {
6418
6776
  for (const eintrag of value.conflicts) {
6419
- if (!isObject8(eintrag) || typeof eintrag.field !== "string" || typeof eintrag.from_image !== "string" || typeof eintrag.from_prompt !== "string") {
6777
+ if (!isObject9(eintrag) || typeof eintrag.field !== "string" || typeof eintrag.from_image !== "string" || typeof eintrag.from_prompt !== "string") {
6420
6778
  befund({
6421
6779
  code: "envelope.conflicts_entry_invalid",
6422
6780
  severity: "error",
@@ -6641,7 +6999,7 @@ var CHAIN_EDGES = {
6641
6999
  scene_ref: { from: "scene_setup", to: "scene" },
6642
7000
  scene_setup_ref: { from: "shot", to: "scene_setup" }
6643
7001
  };
6644
- function istText(wert) {
7002
+ function istText2(wert) {
6645
7003
  return typeof wert === "string" && wert.trim().length > 0;
6646
7004
  }
6647
7005
  function checkDraftChainMeta(meta, type) {
@@ -6652,14 +7010,14 @@ function checkDraftChainMeta(meta, type) {
6652
7010
  };
6653
7011
  }
6654
7012
  const m = meta;
6655
- if (!istText(m.chain_id)) return { ok: false, message: '"chain_id" fehlt oder ist leer.' };
6656
- if (!istText(m.source_run_id)) {
7013
+ if (!istText2(m.chain_id)) return { ok: false, message: '"chain_id" fehlt oder ist leer.' };
7014
+ if (!istText2(m.source_run_id)) {
6657
7015
  return {
6658
7016
  ok: false,
6659
7017
  message: '"source_run_id" fehlt oder ist leer \u2014 ohne sie ist die Herkunft eines Kettenknotens nicht rekonstruierbar (D-96/B3).'
6660
7018
  };
6661
7019
  }
6662
- if (m.source_recovery_id !== void 0 && !istText(m.source_recovery_id)) {
7020
+ if (m.source_recovery_id !== void 0 && !istText2(m.source_recovery_id)) {
6663
7021
  return { ok: false, message: '"source_recovery_id" ist gesetzt, aber leer.' };
6664
7022
  }
6665
7023
  if (!Array.isArray(m.links)) {
@@ -6684,7 +7042,7 @@ function checkDraftChainMeta(meta, type) {
6684
7042
  message: `"${l.field}" gehoert an einen ${kante.from}, nicht an einen ${type}.`
6685
7043
  };
6686
7044
  }
6687
- if (!istText(l.target_element_id) || !istText(l.target_draft_id)) {
7045
+ if (!istText2(l.target_element_id) || !istText2(l.target_draft_id)) {
6688
7046
  return {
6689
7047
  ok: false,
6690
7048
  message: `"links[${index}]" braucht target_element_id und target_draft_id.`
@@ -6739,42 +7097,199 @@ function linkFor(meta, field) {
6739
7097
  return meta?.links.find((l) => l.field === field) ?? null;
6740
7098
  }
6741
7099
 
6742
- // src/lib/szenen/freezeDraftChain.ts
6743
- function ladeKnoten(sicht, elementId, erwarteterTyp) {
6744
- const gelesen = sicht.getElement(elementId);
6745
- if (gelesen.kind !== "ok") {
6746
- return {
6747
- fehler: gelesen.message ?? `Element ${elementId} konnte nicht gelesen werden.`,
6748
- technisch: true
6749
- };
6750
- }
6751
- const snapshot = gelesen.value;
6752
- if (!snapshot) return { fehler: `Element ${elementId} ist unbekannt.` };
6753
- if (snapshot.element.type !== erwarteterTyp) {
6754
- return {
6755
- fehler: `Element ${elementId} ist vom Typ "${snapshot.element.type}", erwartet "${erwarteterTyp}".`
6756
- };
6757
- }
6758
- if (snapshot.draftFork) {
6759
- return {
6760
- fehler: `Element ${elementId} hat parallele Entwuerfe. Solange sie nicht aufgeloest sind, gibt es keinen eindeutigen Kettenknoten (D-29).`
6761
- };
6762
- }
6763
- if (!snapshot.draft) {
6764
- return { fehler: `Element ${elementId} hat keinen Entwurf.` };
6765
- }
6766
- if (!snapshot.draft.chain) {
6767
- return {
6768
- fehler: `Der Entwurf von Element ${elementId} gehoert zu keiner Draft-Kette.`
6769
- };
6770
- }
7100
+ // src/lib/szenen/contextVisibility.ts
7101
+ var isObject10 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
7102
+ function zerlegeKette(contextChain) {
6771
7103
  return {
6772
- type: erwarteterTyp,
6773
- element_id: elementId,
6774
- draft_id: snapshot.draft.draft_id,
6775
- revision: snapshot.draft.revision,
6776
- payload: snapshot.draft.payload,
6777
- chain: snapshot.draft.chain
7104
+ // Das erste Glied unveraendert, `null` eingeschlossen: `null` heisst
7105
+ // kontextlos, nicht „egal" — der Typ von `workingContextId` sagt das
7106
+ // ausdruecklich.
7107
+ workingContextId: contextChain.length > 0 ? contextChain[0] : null,
7108
+ // Gespeicherte Auswahlen tragen nie `null` als Kontext
7109
+ // (`SetPreferredHeadInput.contextId` laeuft durch `checkRequiredId`), das
7110
+ // Schlussglied der Kette kann hier also nichts treffen.
7111
+ inheritanceChain: contextChain.slice(1).filter((link) => typeof link === "string" && link.length > 0)
7112
+ };
7113
+ }
7114
+ function effectivePreferredHead(snapshot, contextChain) {
7115
+ const versionen = snapshot.versions ?? [];
7116
+ if (versionen.length === 0) return null;
7117
+ const { workingContextId, inheritanceChain } = zerlegeKette(contextChain);
7118
+ return resolvePreferredHead({
7119
+ dag: buildVersionDag(versionen),
7120
+ workingContextId,
7121
+ inheritanceChain,
7122
+ owningContextId: snapshot.element.context_id ?? void 0,
7123
+ selections: snapshot.preferredHeads ?? []
7124
+ });
7125
+ }
7126
+ function effectivePreferredHeadSafe(snapshot, contextChain) {
7127
+ try {
7128
+ const outcome = effectivePreferredHead(snapshot, contextChain);
7129
+ return outcome ? { kind: "aufgeloest", outcome } : { kind: "keine_version" };
7130
+ } catch (error) {
7131
+ if (error instanceof VersionDagError) {
7132
+ return { kind: "dag_fehler", message: error.message };
7133
+ }
7134
+ throw error;
7135
+ }
7136
+ }
7137
+ function resolutionOf(result) {
7138
+ return result && result.kind === "aufgeloest" ? result.outcome.resolution : null;
7139
+ }
7140
+ function selectedHeadVersionId(resolution) {
7141
+ return resolution && resolution.kind === "selected" ? resolution.versionId : null;
7142
+ }
7143
+ function usableHeadVersionId(resolution) {
7144
+ if (!resolution) return null;
7145
+ if (resolution.kind === "selected" || resolution.kind === "single") return resolution.versionId;
7146
+ return null;
7147
+ }
7148
+ function preferredHeadRevisionFor(snapshot, contextId) {
7149
+ const auswahl = (snapshot.preferredHeads ?? []).find((h) => h.context_id === contextId);
7150
+ return auswahl?.revision ?? 0;
7151
+ }
7152
+ async function visibleElementsAlongChain(queries, input) {
7153
+ const gesehen = /* @__PURE__ */ new Set();
7154
+ const gefunden = [];
7155
+ const kette = input.contextChain.length > 0 ? input.contextChain : [null];
7156
+ for (const link of kette) {
7157
+ const liste = await queries.listElements({ contextId: link, types: input.types });
7158
+ if (liste.kind !== "ok") return liste;
7159
+ for (const element of liste.value) {
7160
+ if (gesehen.has(element.element_id)) continue;
7161
+ gesehen.add(element.element_id);
7162
+ gefunden.push(element);
7163
+ }
7164
+ }
7165
+ return { kind: "ok", value: gefunden };
7166
+ }
7167
+ async function selectableTargetModels(queries, contextChain) {
7168
+ const selectable = [];
7169
+ const unselectable = [];
7170
+ const entschieden = /* @__PURE__ */ new Set();
7171
+ const kette = contextChain.length > 0 ? contextChain : [null];
7172
+ for (const [chainIndex, link] of kette.entries()) {
7173
+ const liste = await queries.listElements({ contextId: link, type: "target_model" });
7174
+ if (liste.kind !== "ok") return liste;
7175
+ const trefferJeKey = /* @__PURE__ */ new Map();
7176
+ const merke = (key, treffer) => {
7177
+ trefferJeKey.set(key, [...trefferJeKey.get(key) ?? [], treffer]);
7178
+ };
7179
+ for (const element of liste.value) {
7180
+ const detail = await queries.getElement(element.element_id);
7181
+ if (detail.kind !== "ok") return detail;
7182
+ const snapshot = detail.value;
7183
+ if (!snapshot) continue;
7184
+ const titel = snapshot.metadata?.title ?? element.title ?? element.element_id;
7185
+ const aufgeloest = effectivePreferredHeadSafe(snapshot, kette);
7186
+ if (aufgeloest.kind === "dag_fehler") {
7187
+ return {
7188
+ kind: "error",
7189
+ message: `Versionsgraph von ${element.element_id} ist nicht aufbaubar: ` + aufgeloest.message,
7190
+ retryable: false
7191
+ };
7192
+ }
7193
+ if (aufgeloest.kind === "keine_version") continue;
7194
+ const resolution = aufgeloest.outcome.resolution;
7195
+ const payloadVon = (versionId2) => snapshot.versions.find((v) => v.version_id === versionId2)?.payload;
7196
+ const keyVon = (versionId2) => {
7197
+ const payload2 = payloadVon(versionId2);
7198
+ return isObject10(payload2) && typeof payload2.key === "string" ? payload2.key : null;
7199
+ };
7200
+ if (resolution.kind === "fork") {
7201
+ for (const key2 of new Set(resolution.heads.map(keyVon).filter((k) => !!k))) {
7202
+ merke(key2, { art: "fork", elementId: element.element_id, title: titel, heads: resolution.heads });
7203
+ }
7204
+ continue;
7205
+ }
7206
+ const versionId = usableHeadVersionId(resolution);
7207
+ if (!versionId) continue;
7208
+ const key = keyVon(versionId);
7209
+ if (!key) continue;
7210
+ const payload = payloadVon(versionId);
7211
+ merke(key, {
7212
+ art: "aufgeloest",
7213
+ eintrag: {
7214
+ key,
7215
+ title: titel,
7216
+ elementId: element.element_id,
7217
+ versionId,
7218
+ provider: isObject10(payload) && typeof payload.provider === "string" ? payload.provider : null,
7219
+ executionProfiles: isObject10(payload) && Array.isArray(payload.execution_profiles) ? payload.execution_profiles : [],
7220
+ chainIndex
7221
+ }
7222
+ });
7223
+ }
7224
+ for (const [key, treffer] of trefferJeKey) {
7225
+ if (entschieden.has(key)) continue;
7226
+ entschieden.add(key);
7227
+ if (treffer.length > 1) {
7228
+ const namen = treffer.map((t) => t.art === "fork" ? t.title : t.eintrag.title);
7229
+ for (const t of treffer) {
7230
+ unselectable.push({
7231
+ key,
7232
+ elementId: t.art === "fork" ? t.elementId : t.eintrag.elementId,
7233
+ title: t.art === "fork" ? t.title : t.eintrag.title,
7234
+ reason: "ambiguous",
7235
+ message: `\`${key}\` ist in diesem Kontext mehrfach vergeben (${namen.join(", ")}). Die Aufl\xF6sung w\xE4hlt keinen.`
7236
+ });
7237
+ }
7238
+ continue;
7239
+ }
7240
+ const einziger = treffer[0];
7241
+ if (einziger.art === "fork") {
7242
+ unselectable.push({
7243
+ key,
7244
+ elementId: einziger.elementId,
7245
+ title: einziger.title,
7246
+ reason: "fork",
7247
+ message: `\`${key}\` liegt bei \u201E${einziger.title}" auf einem Fork (${einziger.heads.length} K\xF6pfe, keine greifende Auswahl). Erst einen bevorzugten Kopf setzen (D-36) \u2014 ein gleichnamiges Zielmodell aus einem entfernteren Kontext tritt daf\xFCr nicht ein.`
7248
+ });
7249
+ continue;
7250
+ }
7251
+ selectable.push(einziger.eintrag);
7252
+ }
7253
+ }
7254
+ return { kind: "ok", value: { selectable, unselectable } };
7255
+ }
7256
+
7257
+ // src/lib/szenen/freezeDraftChain.ts
7258
+ function ladeKnoten(sicht, elementId, erwarteterTyp) {
7259
+ const gelesen = sicht.getElement(elementId);
7260
+ if (gelesen.kind !== "ok") {
7261
+ return {
7262
+ fehler: gelesen.message ?? `Element ${elementId} konnte nicht gelesen werden.`,
7263
+ technisch: true
7264
+ };
7265
+ }
7266
+ const snapshot = gelesen.value;
7267
+ if (!snapshot) return { fehler: `Element ${elementId} ist unbekannt.` };
7268
+ if (snapshot.element.type !== erwarteterTyp) {
7269
+ return {
7270
+ fehler: `Element ${elementId} ist vom Typ "${snapshot.element.type}", erwartet "${erwarteterTyp}".`
7271
+ };
7272
+ }
7273
+ if (snapshot.draftFork) {
7274
+ return {
7275
+ fehler: `Element ${elementId} hat parallele Entwuerfe. Solange sie nicht aufgeloest sind, gibt es keinen eindeutigen Kettenknoten (D-29).`
7276
+ };
7277
+ }
7278
+ if (!snapshot.draft) {
7279
+ return { fehler: `Element ${elementId} hat keinen Entwurf.` };
7280
+ }
7281
+ if (!snapshot.draft.chain) {
7282
+ return {
7283
+ fehler: `Der Entwurf von Element ${elementId} gehoert zu keiner Draft-Kette.`
7284
+ };
7285
+ }
7286
+ return {
7287
+ type: erwarteterTyp,
7288
+ element_id: elementId,
7289
+ draft_id: snapshot.draft.draft_id,
7290
+ revision: snapshot.draft.revision,
7291
+ payload: snapshot.draft.payload,
7292
+ chain: snapshot.draft.chain
6778
7293
  };
6779
7294
  }
6780
7295
  function ausfallErgebnis(ausfall) {
@@ -6873,6 +7388,113 @@ async function freezeDraftChain(input) {
6873
7388
  ...shot.chain.source_recovery_id ? { sourceRecoveryId: shot.chain.source_recovery_id } : {}
6874
7389
  };
6875
7390
  }
7391
+ function ladeSzene(sicht, elementId, contextChain) {
7392
+ const gelesen = sicht.getElement(elementId);
7393
+ if (gelesen.kind !== "ok") {
7394
+ return {
7395
+ fehler: gelesen.message ?? `Element ${elementId} konnte nicht gelesen werden.`,
7396
+ technisch: true
7397
+ };
7398
+ }
7399
+ const snapshot = gelesen.value;
7400
+ if (!snapshot) return { fehler: `Element ${elementId} ist unbekannt.` };
7401
+ if (snapshot.element.type !== "scene") {
7402
+ return {
7403
+ fehler: `Element ${elementId} ist vom Typ "${snapshot.element.type}", erwartet "scene".`
7404
+ };
7405
+ }
7406
+ if (snapshot.draftFork) {
7407
+ return {
7408
+ fehler: `Element ${elementId} hat parallele Entwuerfe. Solange sie nicht aufgeloest sind, gibt es keinen eindeutigen Arbeitsstand (D-29).`
7409
+ };
7410
+ }
7411
+ if (snapshot.draft) {
7412
+ return {
7413
+ element_id: elementId,
7414
+ draft_id: snapshot.draft.draft_id,
7415
+ revision: snapshot.draft.revision,
7416
+ version_id: null,
7417
+ payload: snapshot.draft.payload
7418
+ };
7419
+ }
7420
+ const versionen = snapshot.versions ?? [];
7421
+ if (versionen.length === 0) {
7422
+ return {
7423
+ fehler: `Element ${elementId} hat weder einen Entwurf noch eine veroeffentlichte Version. Es gibt nichts einzufrieren.`
7424
+ };
7425
+ }
7426
+ const kopf = effectivePreferredHeadSafe(
7427
+ { element: snapshot.element, versions: versionen, preferredHeads: snapshot.preferredHeads },
7428
+ contextChain
7429
+ );
7430
+ if (kopf.kind === "dag_fehler") {
7431
+ return { fehler: `Der Versionsgraph von Element ${elementId} ist nicht aufbaubar: ${kopf.message}` };
7432
+ }
7433
+ const versionId = usableHeadVersionId(resolutionOf(kopf));
7434
+ if (!versionId) {
7435
+ return {
7436
+ fehler: `Element ${elementId} hat mehrere veroeffentlichte Koepfe und in diesem Kontext keine Auswahl. Welcher Stand gilt, entscheidet keine Reihenfolge (D-36) \u2014 bitte einen bevorzugten Kopf setzen.`
7437
+ };
7438
+ }
7439
+ const version = versionen.find((v) => v.version_id === versionId);
7440
+ if (!version) {
7441
+ return {
7442
+ fehler: `Die wirksame Version ${versionId} von Element ${elementId} steht nicht in der gelesenen Momentaufnahme.`
7443
+ };
7444
+ }
7445
+ return {
7446
+ element_id: elementId,
7447
+ draft_id: null,
7448
+ revision: null,
7449
+ version_id: versionId,
7450
+ payload: version.payload
7451
+ };
7452
+ }
7453
+ async function freezeSceneWorkingState(input) {
7454
+ const { sceneElementId, store, resolver, contextChain, userInstruction } = input;
7455
+ const a = await store.readSnapshot({ fresh: false });
7456
+ const szene = ladeSzene(a, sceneElementId, contextChain);
7457
+ if ("fehler" in szene) return ausfallErgebnis(szene);
7458
+ const b = await store.readSnapshot({ fresh: true });
7459
+ const erneut = ladeSzene(b, sceneElementId, contextChain);
7460
+ if ("fehler" in erneut) return ausfallErgebnis(erneut);
7461
+ if (erneut.draft_id !== szene.draft_id || erneut.revision !== szene.revision || erneut.version_id !== szene.version_id) {
7462
+ return {
7463
+ kind: "conflict",
7464
+ message: `Der Arbeitsstand der Szene ${sceneElementId} hat sich waehrend des Einfrierens geaendert (erwartet ${szene.draft_id ? `Entwurf ${szene.draft_id}, Revision ${szene.revision}` : `Version ${szene.version_id}`}, vorhanden ${erneut.draft_id ? `Entwurf ${erneut.draft_id}, Revision ${erneut.revision}` : `Version ${erneut.version_id}`}). Es wurde kein Modell gerufen.`,
7465
+ node: { type: "scene", element_id: sceneElementId, draft_id: szene.draft_id ?? "" },
7466
+ expectedRevision: szene.revision ?? 0,
7467
+ actualRevision: erneut.revision ?? 0
7468
+ };
7469
+ }
7470
+ const aufgeloest = await resolveScenePayload({
7471
+ scenePayload: szene.payload,
7472
+ sceneElementId: szene.element_id,
7473
+ // Ein Entwurf hat keine Version — und bekommt hier auch keine erfundene
7474
+ // (D-98/D-75).
7475
+ sceneVersionId: szene.version_id ?? "",
7476
+ resolver,
7477
+ contextChain,
7478
+ userInstruction
7479
+ });
7480
+ if (aufgeloest.kind !== "resolved") {
7481
+ return {
7482
+ kind: "rejected",
7483
+ message: aufgeloest.failure.message,
7484
+ failure: aufgeloest.failure
7485
+ };
7486
+ }
7487
+ return {
7488
+ kind: "ok",
7489
+ scene: {
7490
+ element_id: szene.element_id,
7491
+ draft_id: szene.draft_id,
7492
+ revision: szene.revision,
7493
+ version_id: szene.version_id
7494
+ },
7495
+ input: aufgeloest.input
7496
+ };
7497
+ }
6876
7498
 
6877
7499
  // src/lib/szenen/sceneDerivationRecovery.ts
6878
7500
  function recoveryStatusOf(assessment) {
@@ -6905,13 +7527,13 @@ function isSzenenItemId(itemId) {
6905
7527
  return itemId.startsWith(SZENEN_ITEM_PREFIX);
6906
7528
  }
6907
7529
  function checkSzenenBatchOrigin(candidate) {
6908
- if (!istText2(candidate.prompt_run_id)) {
7530
+ if (!istText3(candidate.prompt_run_id)) {
6909
7531
  return {
6910
7532
  kind: "rejected",
6911
7533
  failure: { field: "prompt_run_id", message: '"prompt_run_id" fehlt oder ist leer.' }
6912
7534
  };
6913
7535
  }
6914
- if (!istText2(candidate.generation_batch_id)) {
7536
+ if (!istText3(candidate.generation_batch_id)) {
6915
7537
  return {
6916
7538
  kind: "rejected",
6917
7539
  failure: {
@@ -6954,7 +7576,7 @@ function mergeSzenenBatchOrigin(bestehend, neu) {
6954
7576
  };
6955
7577
  }
6956
7578
  var DEFAULT_FSK_LEVEL = "FSK16";
6957
- var istText2 = (v) => typeof v === "string" && v.trim().length > 0;
7579
+ var istText3 = (v) => typeof v === "string" && v.trim().length > 0;
6958
7580
  function roundOfRun(run, runsOfShot) {
6959
7581
  return runsOfShot.findIndex((kandidat) => kandidat.run_id === run.run_id) + 1;
6960
7582
  }
@@ -6990,7 +7612,7 @@ function deriveItemFromRun(input) {
6990
7612
  }
6991
7613
  };
6992
7614
  }
6993
- if (!run.output || !istText2(run.output.positive)) {
7615
+ if (!run.output || !istText3(run.output.positive)) {
6994
7616
  return {
6995
7617
  kind: "rejected",
6996
7618
  failure: {
@@ -7011,8 +7633,8 @@ function deriveItemFromRun(input) {
7011
7633
  }
7012
7634
  const item_id = itemIdForRun(run.run_id);
7013
7635
  const lineage = deriveLineage(item_id, round, existingItems);
7014
- const negative = istText2(run.output.negative) ? run.output.negative : null;
7015
- const title = istText2(input.title) ? input.title : istText2(input.shotTitle) ? `${input.shotTitle} \xB7 Runde ${round}` : `Szenen-Lauf ${round}`;
7636
+ const negative = istText3(run.output.negative) ? run.output.negative : null;
7637
+ const title = istText3(input.title) ? input.title : istText3(input.shotTitle) ? `${input.shotTitle} \xB7 Runde ${round}` : `Szenen-Lauf ${round}`;
7016
7638
  return {
7017
7639
  kind: "ok",
7018
7640
  value: {
@@ -7022,9 +7644,9 @@ function deriveItemFromRun(input) {
7022
7644
  negative_prompt: negative,
7023
7645
  // `feedback` ist Pflicht (D-55) und ist genau die Erlaeuterung fuer den
7024
7646
  // Menschen — also gehoert sie in das Feld fuer Notizen.
7025
- notes: istText2(input.notes) ? input.notes : run.output.feedback,
7647
+ notes: istText3(input.notes) ? input.notes : run.output.feedback,
7026
7648
  rating: typeof input.rating === "number" ? input.rating : 0,
7027
- fsk_level: istText2(input.fskLevel) ? input.fskLevel : DEFAULT_FSK_LEVEL,
7649
+ fsk_level: istText3(input.fskLevel) ? input.fskLevel : DEFAULT_FSK_LEVEL,
7028
7650
  tags: [],
7029
7651
  szenen: {
7030
7652
  prompt_run_id: run.run_id,
@@ -7049,7 +7671,7 @@ function deriveItemFromRun(input) {
7049
7671
  }
7050
7672
 
7051
7673
  // src/lib/szenen/imageGenerationOrderStore.ts
7052
- function istText3(wert) {
7674
+ function istText4(wert) {
7053
7675
  return typeof wert === "string" && wert.trim().length > 0;
7054
7676
  }
7055
7677
  function collectImageGenerationOrders(events) {
@@ -7057,7 +7679,7 @@ function collectImageGenerationOrders(events) {
7057
7679
  for (const event of events) {
7058
7680
  if (event.type !== SZENEN_EVENT_TYPES.imageGenerationStarted) continue;
7059
7681
  const payload = event.payload;
7060
- if (!payload || !istText3(payload.generation_batch_id) || !istText3(payload.prompt_run_id)) continue;
7682
+ if (!payload || !istText4(payload.generation_batch_id) || !istText4(payload.prompt_run_id)) continue;
7061
7683
  if (byBatchId.has(payload.generation_batch_id)) continue;
7062
7684
  byBatchId.set(payload.generation_batch_id, {
7063
7685
  generation_batch_id: payload.generation_batch_id,
@@ -7071,7 +7693,7 @@ function collectImageGenerationOrders(events) {
7071
7693
  for (const event of events) {
7072
7694
  if (event.type !== SZENEN_EVENT_TYPES.imageGenerationFinished) continue;
7073
7695
  const payload = event.payload;
7074
- if (!payload || !istText3(payload.generation_batch_id)) continue;
7696
+ if (!payload || !istText4(payload.generation_batch_id)) continue;
7075
7697
  const auftrag = byBatchId.get(payload.generation_batch_id);
7076
7698
  if (!auftrag) continue;
7077
7699
  if (auftrag.status !== "started") continue;
@@ -9723,180 +10345,23 @@ function createHfImageLibrary(options) {
9723
10345
  };
9724
10346
  }
9725
10347
 
9726
- // src/lib/szenen/contextVisibility.ts
9727
- var isObject9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
9728
- function zerlegeKette(contextChain) {
9729
- return {
9730
- // Das erste Glied unveraendert, `null` eingeschlossen: `null` heisst
9731
- // kontextlos, nicht „egal" — der Typ von `workingContextId` sagt das
9732
- // ausdruecklich.
9733
- workingContextId: contextChain.length > 0 ? contextChain[0] : null,
9734
- // Gespeicherte Auswahlen tragen nie `null` als Kontext
9735
- // (`SetPreferredHeadInput.contextId` laeuft durch `checkRequiredId`), das
9736
- // Schlussglied der Kette kann hier also nichts treffen.
9737
- inheritanceChain: contextChain.slice(1).filter((link) => typeof link === "string" && link.length > 0)
9738
- };
9739
- }
9740
- function effectivePreferredHead(snapshot, contextChain) {
9741
- const versionen = snapshot.versions ?? [];
9742
- if (versionen.length === 0) return null;
9743
- const { workingContextId, inheritanceChain } = zerlegeKette(contextChain);
9744
- return resolvePreferredHead({
9745
- dag: buildVersionDag(versionen),
9746
- workingContextId,
9747
- inheritanceChain,
9748
- owningContextId: snapshot.element.context_id ?? void 0,
9749
- selections: snapshot.preferredHeads ?? []
9750
- });
9751
- }
9752
- function effectivePreferredHeadSafe(snapshot, contextChain) {
9753
- try {
9754
- const outcome = effectivePreferredHead(snapshot, contextChain);
9755
- return outcome ? { kind: "aufgeloest", outcome } : { kind: "keine_version" };
9756
- } catch (error) {
9757
- if (error instanceof VersionDagError) {
9758
- return { kind: "dag_fehler", message: error.message };
9759
- }
9760
- throw error;
9761
- }
9762
- }
9763
- function resolutionOf(result) {
9764
- return result && result.kind === "aufgeloest" ? result.outcome.resolution : null;
9765
- }
9766
- function selectedHeadVersionId(resolution) {
9767
- return resolution && resolution.kind === "selected" ? resolution.versionId : null;
9768
- }
9769
- function usableHeadVersionId(resolution) {
9770
- if (!resolution) return null;
9771
- if (resolution.kind === "selected" || resolution.kind === "single") return resolution.versionId;
9772
- return null;
9773
- }
9774
- function preferredHeadRevisionFor(snapshot, contextId) {
9775
- const auswahl = (snapshot.preferredHeads ?? []).find((h) => h.context_id === contextId);
9776
- return auswahl?.revision ?? 0;
9777
- }
9778
- async function visibleElementsAlongChain(queries, input) {
9779
- const gesehen = /* @__PURE__ */ new Set();
9780
- const gefunden = [];
9781
- const kette = input.contextChain.length > 0 ? input.contextChain : [null];
9782
- for (const link of kette) {
9783
- const liste = await queries.listElements({ contextId: link, types: input.types });
9784
- if (liste.kind !== "ok") return liste;
9785
- for (const element of liste.value) {
9786
- if (gesehen.has(element.element_id)) continue;
9787
- gesehen.add(element.element_id);
9788
- gefunden.push(element);
9789
- }
9790
- }
9791
- return { kind: "ok", value: gefunden };
9792
- }
9793
- async function selectableTargetModels(queries, contextChain) {
9794
- const selectable = [];
9795
- const unselectable = [];
9796
- const entschieden = /* @__PURE__ */ new Set();
9797
- const kette = contextChain.length > 0 ? contextChain : [null];
9798
- for (const [chainIndex, link] of kette.entries()) {
9799
- const liste = await queries.listElements({ contextId: link, type: "target_model" });
9800
- if (liste.kind !== "ok") return liste;
9801
- const trefferJeKey = /* @__PURE__ */ new Map();
9802
- const merke = (key, treffer) => {
9803
- trefferJeKey.set(key, [...trefferJeKey.get(key) ?? [], treffer]);
9804
- };
9805
- for (const element of liste.value) {
9806
- const detail = await queries.getElement(element.element_id);
9807
- if (detail.kind !== "ok") return detail;
9808
- const snapshot = detail.value;
9809
- if (!snapshot) continue;
9810
- const titel = snapshot.metadata?.title ?? element.title ?? element.element_id;
9811
- const aufgeloest = effectivePreferredHeadSafe(snapshot, kette);
9812
- if (aufgeloest.kind === "dag_fehler") {
9813
- return {
9814
- kind: "error",
9815
- message: `Versionsgraph von ${element.element_id} ist nicht aufbaubar: ` + aufgeloest.message,
9816
- retryable: false
9817
- };
9818
- }
9819
- if (aufgeloest.kind === "keine_version") continue;
9820
- const resolution = aufgeloest.outcome.resolution;
9821
- const payloadVon = (versionId2) => snapshot.versions.find((v) => v.version_id === versionId2)?.payload;
9822
- const keyVon = (versionId2) => {
9823
- const payload2 = payloadVon(versionId2);
9824
- return isObject9(payload2) && typeof payload2.key === "string" ? payload2.key : null;
9825
- };
9826
- if (resolution.kind === "fork") {
9827
- for (const key2 of new Set(resolution.heads.map(keyVon).filter((k) => !!k))) {
9828
- merke(key2, { art: "fork", elementId: element.element_id, title: titel, heads: resolution.heads });
9829
- }
9830
- continue;
9831
- }
9832
- const versionId = usableHeadVersionId(resolution);
9833
- if (!versionId) continue;
9834
- const key = keyVon(versionId);
9835
- if (!key) continue;
9836
- const payload = payloadVon(versionId);
9837
- merke(key, {
9838
- art: "aufgeloest",
9839
- eintrag: {
9840
- key,
9841
- title: titel,
9842
- elementId: element.element_id,
9843
- versionId,
9844
- provider: isObject9(payload) && typeof payload.provider === "string" ? payload.provider : null,
9845
- executionProfiles: isObject9(payload) && Array.isArray(payload.execution_profiles) ? payload.execution_profiles : [],
9846
- chainIndex
9847
- }
9848
- });
9849
- }
9850
- for (const [key, treffer] of trefferJeKey) {
9851
- if (entschieden.has(key)) continue;
9852
- entschieden.add(key);
9853
- if (treffer.length > 1) {
9854
- const namen = treffer.map((t) => t.art === "fork" ? t.title : t.eintrag.title);
9855
- for (const t of treffer) {
9856
- unselectable.push({
9857
- key,
9858
- elementId: t.art === "fork" ? t.elementId : t.eintrag.elementId,
9859
- title: t.art === "fork" ? t.title : t.eintrag.title,
9860
- reason: "ambiguous",
9861
- message: `\`${key}\` ist in diesem Kontext mehrfach vergeben (${namen.join(", ")}). Die Aufl\xF6sung w\xE4hlt keinen.`
9862
- });
9863
- }
9864
- continue;
9865
- }
9866
- const einziger = treffer[0];
9867
- if (einziger.art === "fork") {
9868
- unselectable.push({
9869
- key,
9870
- elementId: einziger.elementId,
9871
- title: einziger.title,
9872
- reason: "fork",
9873
- message: `\`${key}\` liegt bei \u201E${einziger.title}" auf einem Fork (${einziger.heads.length} K\xF6pfe, keine greifende Auswahl). Erst einen bevorzugten Kopf setzen (D-36) \u2014 ein gleichnamiges Zielmodell aus einem entfernteren Kontext tritt daf\xFCr nicht ein.`
9874
- });
9875
- continue;
9876
- }
9877
- selectable.push(einziger.eintrag);
9878
- }
9879
- }
9880
- return { kind: "ok", value: { selectable, unselectable } };
9881
- }
9882
-
9883
10348
  // src/lib/szenen/imageGenerationCapability.ts
9884
- var isObject10 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
9885
- var istText4 = (v) => typeof v === "string" && v.trim().length > 0;
10349
+ var isObject11 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
10350
+ var istText5 = (v) => typeof v === "string" && v.trim().length > 0;
9886
10351
  function checkImageExecutionProfile(profile) {
9887
10352
  const befunde = [];
9888
- if (!isObject10(profile)) return ["Das Ausfuehrungsprofil ist kein Objekt."];
10353
+ if (!isObject11(profile)) return ["Das Ausfuehrungsprofil ist kein Objekt."];
9889
10354
  for (const feld of ["profile_id", "execution_path", "execution_model_id"]) {
9890
- if (!istText4(profile[feld])) befunde.push(`"${feld}" fehlt als nicht-leerer Text.`);
10355
+ if (!istText5(profile[feld])) befunde.push(`"${feld}" fehlt als nicht-leerer Text.`);
9891
10356
  }
9892
10357
  if (typeof profile.enabled !== "boolean") befunde.push('"enabled" fehlt als Boolean.');
9893
- if (!Array.isArray(profile.environments) || profile.environments.length === 0 || !profile.environments.every(istText4)) {
10358
+ if (!Array.isArray(profile.environments) || profile.environments.length === 0 || !profile.environments.every(istText5)) {
9894
10359
  befunde.push('"environments" fehlt als nicht-leere Liste von Umgebungskennungen.');
9895
10360
  }
9896
10361
  if (!Number.isInteger(profile.max_images) || profile.max_images < 1) {
9897
10362
  befunde.push(`"max_images" ist ${JSON.stringify(profile.max_images)}; erwartet eine ganze Zahl >= 1.`);
9898
10363
  }
9899
- if (!Array.isArray(profile.aspect_ratios) || !profile.aspect_ratios.every(istText4)) {
10364
+ if (!Array.isArray(profile.aspect_ratios) || !profile.aspect_ratios.every(istText5)) {
9900
10365
  befunde.push('"aspect_ratios" fehlt als Liste von Seitenverhaeltnissen (darf leer sein).');
9901
10366
  }
9902
10367
  if (typeof profile.accepts_seed !== "boolean") befunde.push('"accepts_seed" fehlt als Boolean.');
@@ -9905,10 +10370,26 @@ function checkImageExecutionProfile(profile) {
9905
10370
  }
9906
10371
  return befunde;
9907
10372
  }
10373
+ function checkImageExecutionProfiles(profiles) {
10374
+ const anzahlJeKennung = /* @__PURE__ */ new Map();
10375
+ for (const profil of profiles ?? []) {
10376
+ if (!isObject11(profil) || !istText5(profil.profile_id)) continue;
10377
+ anzahlJeKennung.set(profil.profile_id, (anzahlJeKennung.get(profil.profile_id) ?? 0) + 1);
10378
+ }
10379
+ return (profiles ?? []).map((profil) => {
10380
+ const befunde = [...checkImageExecutionProfile(profil)];
10381
+ if (isObject11(profil) && istText5(profil.profile_id) && (anzahlJeKennung.get(profil.profile_id) ?? 0) > 1) {
10382
+ befunde.push(
10383
+ `Die profile_id "${profil.profile_id}" kommt in diesem Zielmodell mehrfach vor \u2014 die Auswahl waere nicht mehr eindeutig aufloesbar.`
10384
+ );
10385
+ }
10386
+ return befunde;
10387
+ });
10388
+ }
9908
10389
  function executableImageModels(promptTargetModelKey, targets, capability) {
9909
10390
  const models = [];
9910
10391
  const invalid = [];
9911
- if (!istText4(capability?.environment_id) || !Array.isArray(capability?.execution_paths)) {
10392
+ if (!istText5(capability?.environment_id) || !Array.isArray(capability?.execution_paths)) {
9912
10393
  return {
9913
10394
  prompt_target_model_key: promptTargetModelKey,
9914
10395
  models: [],
@@ -9918,23 +10399,31 @@ function executableImageModels(promptTargetModelKey, targets, capability) {
9918
10399
  };
9919
10400
  }
9920
10401
  for (const target of targets ?? []) {
9921
- for (const roh of target.executionProfiles ?? []) {
9922
- const befunde = checkImageExecutionProfile(roh);
10402
+ const profilBefunde = checkImageExecutionProfiles(target.executionProfiles ?? []);
10403
+ for (const [index, roh] of (target.executionProfiles ?? []).entries()) {
10404
+ const befunde = profilBefunde[index] ?? [];
9923
10405
  if (befunde.length > 0) {
9924
- const kennung = isObject10(roh) && istText4(roh.profile_id) ? roh.profile_id : "(ohne profile_id)";
10406
+ const kennung = isObject11(roh) && istText5(roh.profile_id) ? roh.profile_id : "(ohne profile_id)";
9925
10407
  invalid.push(`${target.key}/${kennung}: ${befunde.join(" ")}`);
9926
10408
  continue;
9927
10409
  }
9928
10410
  const profil = roh;
9929
10411
  if (!profil.enabled) continue;
9930
10412
  if (!profil.environments.includes(capability.environment_id)) continue;
9931
- if (!capability.execution_paths.includes(profil.execution_path)) continue;
10413
+ const weg = capability.execution_paths.find((r) => r.execution_path === profil.execution_path);
10414
+ if (!weg) continue;
10415
+ if (target.provider !== weg.provider) {
10416
+ invalid.push(
10417
+ `${target.key}/${profil.profile_id}: Das Zielmodell nennt den Anbieter ${target.provider === null ? "(keinen)" : `"${target.provider}"`}, der Aufrufweg "${weg.execution_path}" fuehrt aber zu "${weg.provider}".`
10418
+ );
10419
+ continue;
10420
+ }
9932
10421
  models.push({
9933
10422
  selection_id: `${target.key}#${profil.profile_id}`,
9934
10423
  target_model_key: target.key,
9935
10424
  ...target.versionId ? { target_model_version_id: target.versionId } : {},
9936
10425
  display_name: target.title,
9937
- provider: target.provider ?? "(ohne provider)",
10426
+ provider: weg.provider,
9938
10427
  profile_id: profil.profile_id,
9939
10428
  environment_id: capability.environment_id,
9940
10429
  execution_path: profil.execution_path,
@@ -9953,7 +10442,7 @@ function executableImageModels(promptTargetModelKey, targets, capability) {
9953
10442
  models: [],
9954
10443
  default_selection_id: null,
9955
10444
  invalid_profiles: invalid,
9956
- reason: `In dieser Umgebung (${capability.environment_id}) traegt kein sichtbares Zielmodell ein aktives Ausfuehrungsprofil fuer einen Aufrufweg dieses Hosts (${capability.execution_paths.join(", ") || "keiner"}).`
10445
+ reason: `In dieser Umgebung (${capability.environment_id}) traegt kein sichtbares Zielmodell ein aktives Ausfuehrungsprofil fuer einen Aufrufweg dieses Hosts (${capability.execution_paths.map((r) => r.execution_path).join(", ") || "keiner"}).`
9957
10446
  };
9958
10447
  }
9959
10448
  const passend = models.find((m) => m.is_prompt_target);
@@ -10196,7 +10685,7 @@ function createImageGenerationPort(options) {
10196
10685
  // src/lib/szenen/memoryViewPort.ts
10197
10686
  var MEMORY_IMAGE_CAPABILITY = {
10198
10687
  environment_id: "memory",
10199
- execution_paths: ["memory"]
10688
+ execution_paths: [{ execution_path: "memory", provider: "google" }]
10200
10689
  };
10201
10690
  function ok2(value) {
10202
10691
  return { kind: "ok", value };
@@ -10323,6 +10812,44 @@ function createMemoryViewPort(options = {}) {
10323
10812
  return ok2(laeufe.filter(
10324
10813
  (r) => r.source?.kind === "draft_chain" && r.source.chain_id === chainId
10325
10814
  ));
10815
+ },
10816
+ // ── Der Lauf direkt aus einer Szene (D-135) ───────────────────────────
10817
+ //
10818
+ // Wie beim Kettenlauf bildet der Speicherport nur die **Form** ab: ein
10819
+ // Lauf mit `source.kind === 'scene_direct'`, ohne Shot und ohne
10820
+ // Versionskennungen. Ob ein Arbeitsstand einfrierbar ist, entscheidet
10821
+ // `clientRunPort` gegen einen echten Speicher — hier waere es eine zweite
10822
+ // Wahrheit.
10823
+ async startRunFromScene(input) {
10824
+ const runId = ids();
10825
+ const basis = (options.deriveRun ?? simulierterLauf)(
10826
+ { shotVersionId: "", ...input.userInstruction ? { userInstruction: input.userInstruction } : {} },
10827
+ runId
10828
+ );
10829
+ const lauf = {
10830
+ ...basis,
10831
+ shot_version_id: "",
10832
+ shot_element_id: "",
10833
+ scene_setup_version_id: "",
10834
+ camera_id: "",
10835
+ target_model_version_id: "",
10836
+ source: {
10837
+ kind: "scene_direct",
10838
+ scene: {
10839
+ element_id: input.sceneElementId,
10840
+ draft_id: `draft-${input.sceneElementId}`,
10841
+ revision: 1,
10842
+ version_id: null
10843
+ }
10844
+ }
10845
+ };
10846
+ laeufe.push(lauf);
10847
+ return done(lauf);
10848
+ },
10849
+ async listRunsForScene(sceneElementId) {
10850
+ return ok2(laeufe.filter(
10851
+ (r) => r.source?.kind === "scene_direct" && r.source.scene.element_id === sceneElementId
10852
+ ));
10326
10853
  }
10327
10854
  };
10328
10855
  const itemPort = {
@@ -11408,6 +11935,23 @@ function createEventLogRunPersistence(channel) {
11408
11935
  return queryError2(error, `Laeufe der Kette ${chainId} konnten nicht gelesen werden`);
11409
11936
  }
11410
11937
  },
11938
+ async listForScene(sceneElementId) {
11939
+ try {
11940
+ const events = await channel.readEvents();
11941
+ return {
11942
+ kind: "ok",
11943
+ value: collectPromptRuns(events).filter((run) => {
11944
+ const quelle = sourceOf(run);
11945
+ return quelle.kind === "scene_direct" && quelle.scene.element_id === sceneElementId;
11946
+ })
11947
+ };
11948
+ } catch (error) {
11949
+ return queryError2(
11950
+ error,
11951
+ `Laeufe der Szene ${sceneElementId} konnten nicht gelesen werden`
11952
+ );
11953
+ }
11954
+ },
11411
11955
  async record(record) {
11412
11956
  try {
11413
11957
  await channel.appendEvent(SZENEN_EVENT_TYPES.promptRunRecorded, record);
@@ -11494,13 +12038,21 @@ function createClientRunPort(options) {
11494
12038
  return { kind: "error", message: resolved.failure.message, retryable: false };
11495
12039
  }
11496
12040
  const outcome = await runPromptDerivation(resolved.input, text);
12041
+ if (!resolved.input.shot) {
12042
+ return {
12043
+ kind: "error",
12044
+ message: `Die Aufloesung der Shot-Version ${input.shotVersionId} lieferte eine Eingabe ohne Shot. Das ist ein Programmfehler, kein Lauf.`,
12045
+ retryable: false
12046
+ };
12047
+ }
11497
12048
  const record = {
11498
12049
  run_id: newRunId(),
11499
12050
  shot_version_id: input.shotVersionId,
11500
12051
  shot_element_id: resolved.input.shot.element_id,
11501
12052
  scene_setup_version_id: resolved.input.scene.version_id,
11502
- camera_id: resolved.input.shot.camera_id,
11503
- target_model_version_id: resolved.input.target_model_resolution.version_id,
12053
+ // Leer heisst „kein Wert", nicht „Wert unbekannt" (D-75/D-135).
12054
+ camera_id: resolved.input.shot.camera_id ?? "",
12055
+ target_model_version_id: resolved.input.target_model_resolution?.version_id ?? "",
11504
12056
  provider: outcome.provider,
11505
12057
  model_id: outcome.model_id,
11506
12058
  system_prompt: outcome.system_prompt,
@@ -11515,24 +12067,117 @@ function createClientRunPort(options) {
11515
12067
  } catch (error) {
11516
12068
  return {
11517
12069
  kind: "error",
11518
- message: `Prompt-Lauf fuer Shot-Version ${input.shotVersionId} ist fehlgeschlagen: ${error instanceof Error ? error.message : String(error)}`,
12070
+ message: `Prompt-Lauf fuer Shot-Version ${input.shotVersionId} ist fehlgeschlagen: ${error instanceof Error ? error.message : String(error)}`,
12071
+ retryable: true
12072
+ };
12073
+ }
12074
+ },
12075
+ // ── Der Lauf aus einer Draft-Kette (Stufe 6.6, C3) ─────────────────────
12076
+ async startRunFromDraft(input) {
12077
+ try {
12078
+ let contextId = input.contextId;
12079
+ if (contextId === void 0) {
12080
+ const element = await elements.getElement(input.shotElementId);
12081
+ if (element.kind !== "ok") {
12082
+ return { kind: "error", message: element.message, retryable: element.retryable };
12083
+ }
12084
+ if (element.value === null) {
12085
+ return {
12086
+ kind: "error",
12087
+ message: `Element ${input.shotElementId} ist unbekannt.`,
12088
+ retryable: false
12089
+ };
12090
+ }
12091
+ contextId = element.value.element.context_id;
12092
+ }
12093
+ const chain = await context.chainFor(contextId ?? null);
12094
+ if (chain.kind !== "ok") {
12095
+ return { kind: "error", message: chain.message, retryable: chain.retryable };
12096
+ }
12097
+ const eingefroren = await freezeDraftChain({
12098
+ shotElementId: input.shotElementId,
12099
+ store: elements,
12100
+ resolver,
12101
+ contextChain: chain.value,
12102
+ userInstruction: input.userInstruction ?? null
12103
+ });
12104
+ if (eingefroren.kind === "conflict") {
12105
+ return {
12106
+ kind: "conflict",
12107
+ message: eingefroren.message,
12108
+ node: eingefroren.node,
12109
+ expectedRevision: eingefroren.expectedRevision,
12110
+ actualRevision: eingefroren.actualRevision
12111
+ };
12112
+ }
12113
+ if (eingefroren.kind === "error") {
12114
+ return { kind: "error", message: eingefroren.message, retryable: eingefroren.retryable };
12115
+ }
12116
+ if (eingefroren.kind !== "ok") {
12117
+ return { kind: "rejected", message: eingefroren.message };
12118
+ }
12119
+ const outcome = await runPromptDerivation(eingefroren.input, text);
12120
+ const record = {
12121
+ run_id: newRunId(),
12122
+ // Keine fingierten Versionskennungen (D-98). Was es nicht gibt,
12123
+ // bleibt leer — die Herkunft steht in `source`.
12124
+ shot_version_id: "",
12125
+ shot_element_id: input.shotElementId,
12126
+ scene_setup_version_id: "",
12127
+ camera_id: eingefroren.input.shot?.camera_id ?? "",
12128
+ target_model_version_id: eingefroren.input.target_model_resolution?.version_id ?? "",
12129
+ provider: outcome.provider,
12130
+ model_id: outcome.model_id,
12131
+ system_prompt: outcome.system_prompt,
12132
+ input_payload: eingefroren.input,
12133
+ status: outcome.status,
12134
+ failure: outcome.status === "failed" ? outcome.failure : null,
12135
+ output: outcome.status === "succeeded" ? outcome.output : null,
12136
+ raw_output: outcome.raw_output,
12137
+ source: {
12138
+ kind: "draft_chain",
12139
+ chain_id: eingefroren.chainId,
12140
+ nodes: eingefroren.nodes,
12141
+ // D-123/A2 — die Rekonstruktionsherkunft der Kette wird additiv in
12142
+ // den unveraenderlichen Lauf uebernommen, damit 6.7 die
12143
+ // Input-Bilder auch dann noch findet, wenn die veraenderliche
12144
+ // Kette spaeter nicht mehr existiert.
12145
+ derivation_run_id: eingefroren.sourceRunId,
12146
+ ...eingefroren.sourceRecoveryId ? { derivation_recovery_id: eingefroren.sourceRecoveryId } : {}
12147
+ },
12148
+ created_at: now().toISOString()
12149
+ };
12150
+ return await runs.record(record);
12151
+ } catch (error) {
12152
+ return {
12153
+ kind: "error",
12154
+ message: `Prompt-Lauf aus der Draft-Kette von Element ${input.shotElementId} ist fehlgeschlagen: ${error instanceof Error ? error.message : String(error)}`,
11519
12155
  retryable: true
11520
12156
  };
11521
12157
  }
11522
12158
  },
11523
- // ── Der Lauf aus einer Draft-Kette (Stufe 6.6, C3) ─────────────────────
11524
- async startRunFromDraft(input) {
12159
+ async listRunsForChain(chainId) {
12160
+ const alle = await runs.listForChain(chainId);
12161
+ return alle;
12162
+ },
12163
+ // ── Der Lauf direkt aus einer Szene (D-135) ───────────────────────────
12164
+ //
12165
+ // Bewusst **derselbe** Ablauf wie oben: Kontext ermitteln, Kette
12166
+ // aufloesen, einfrieren, dann erst rufen. Was sich unterscheidet, ist
12167
+ // ausschliesslich, **was** eingefroren wird — ein Szenen-Arbeitsstand
12168
+ // statt einer Drei-Knoten-Kette.
12169
+ async startRunFromScene(input) {
11525
12170
  try {
11526
12171
  let contextId = input.contextId;
11527
12172
  if (contextId === void 0) {
11528
- const element = await elements.getElement(input.shotElementId);
12173
+ const element = await elements.getElement(input.sceneElementId);
11529
12174
  if (element.kind !== "ok") {
11530
12175
  return { kind: "error", message: element.message, retryable: element.retryable };
11531
12176
  }
11532
12177
  if (element.value === null) {
11533
12178
  return {
11534
12179
  kind: "error",
11535
- message: `Element ${input.shotElementId} ist unbekannt.`,
12180
+ message: `Element ${input.sceneElementId} ist unbekannt.`,
11536
12181
  retryable: false
11537
12182
  };
11538
12183
  }
@@ -11542,8 +12187,8 @@ function createClientRunPort(options) {
11542
12187
  if (chain.kind !== "ok") {
11543
12188
  return { kind: "error", message: chain.message, retryable: chain.retryable };
11544
12189
  }
11545
- const eingefroren = await freezeDraftChain({
11546
- shotElementId: input.shotElementId,
12190
+ const eingefroren = await freezeSceneWorkingState({
12191
+ sceneElementId: input.sceneElementId,
11547
12192
  store: elements,
11548
12193
  resolver,
11549
12194
  contextChain: chain.value,
@@ -11567,13 +12212,13 @@ function createClientRunPort(options) {
11567
12212
  const outcome = await runPromptDerivation(eingefroren.input, text);
11568
12213
  const record = {
11569
12214
  run_id: newRunId(),
11570
- // Keine fingierten Versionskennungen (D-98). Was es nicht gibt,
11571
- // bleibt leer — die Herkunft steht in `source`.
12215
+ // Keine fingierten Kennungen (D-98/D-75). Was es nicht gibt, bleibt
12216
+ // leer — die Herkunft steht in `source`.
11572
12217
  shot_version_id: "",
11573
- shot_element_id: input.shotElementId,
12218
+ shot_element_id: "",
11574
12219
  scene_setup_version_id: "",
11575
- camera_id: eingefroren.input.shot.camera_id,
11576
- target_model_version_id: eingefroren.input.target_model_resolution.version_id,
12220
+ camera_id: "",
12221
+ target_model_version_id: eingefroren.input.target_model_resolution?.version_id ?? "",
11577
12222
  provider: outcome.provider,
11578
12223
  model_id: outcome.model_id,
11579
12224
  system_prompt: outcome.system_prompt,
@@ -11582,31 +12227,27 @@ function createClientRunPort(options) {
11582
12227
  failure: outcome.status === "failed" ? outcome.failure : null,
11583
12228
  output: outcome.status === "succeeded" ? outcome.output : null,
11584
12229
  raw_output: outcome.raw_output,
11585
- source: {
11586
- kind: "draft_chain",
11587
- chain_id: eingefroren.chainId,
11588
- nodes: eingefroren.nodes,
11589
- // D-123/A2 — die Rekonstruktionsherkunft der Kette wird additiv in
11590
- // den unveraenderlichen Lauf uebernommen, damit 6.7 die
11591
- // Input-Bilder auch dann noch findet, wenn die veraenderliche
11592
- // Kette spaeter nicht mehr existiert.
11593
- derivation_run_id: eingefroren.sourceRunId,
11594
- ...eingefroren.sourceRecoveryId ? { derivation_recovery_id: eingefroren.sourceRecoveryId } : {}
11595
- },
12230
+ source: { kind: "scene_direct", scene: eingefroren.scene },
11596
12231
  created_at: now().toISOString()
11597
12232
  };
11598
12233
  return await runs.record(record);
11599
12234
  } catch (error) {
11600
12235
  return {
11601
12236
  kind: "error",
11602
- message: `Prompt-Lauf aus der Draft-Kette von Element ${input.shotElementId} ist fehlgeschlagen: ${error instanceof Error ? error.message : String(error)}`,
12237
+ message: `Prompt-Lauf aus der Szene ${input.sceneElementId} ist fehlgeschlagen: ${error instanceof Error ? error.message : String(error)}`,
11603
12238
  retryable: true
11604
12239
  };
11605
12240
  }
11606
12241
  },
11607
- async listRunsForChain(chainId) {
11608
- const alle = await runs.listForChain(chainId);
11609
- return alle;
12242
+ async listRunsForScene(sceneElementId) {
12243
+ try {
12244
+ return await runs.listForScene(sceneElementId);
12245
+ } catch (error) {
12246
+ return queryError2(
12247
+ error,
12248
+ `Laeufe der Szene ${sceneElementId} konnten nicht gelesen werden`
12249
+ );
12250
+ }
11610
12251
  }
11611
12252
  };
11612
12253
  }
@@ -11671,18 +12312,18 @@ function createFlowImageProvider(generateImage) {
11671
12312
  }
11672
12313
 
11673
12314
  // src/lib/szenen/imageBatchStore.ts
11674
- var istText5 = (wert) => typeof wert === "string" && wert.trim().length > 0;
12315
+ var istText6 = (wert) => typeof wert === "string" && wert.trim().length > 0;
11675
12316
  function alsBilder(rohe) {
11676
12317
  if (!Array.isArray(rohe)) return [];
11677
- return rohe.filter((b) => !!b && typeof b === "object").filter((b) => istText5(b.media_ref) && typeof b.position === "number").map((b) => ({
12318
+ return rohe.filter((b) => !!b && typeof b === "object").filter((b) => istText6(b.media_ref) && typeof b.position === "number").map((b) => ({
11678
12319
  media_ref: b.media_ref,
11679
12320
  position: b.position,
11680
- ...istText5(b.asset_id) ? { asset_id: b.asset_id } : {},
12321
+ ...istText6(b.asset_id) ? { asset_id: b.asset_id } : {},
11681
12322
  // Der bestätigte MIME-Typ (Review 2026-08-18 §5 P2) muss durch das
11682
12323
  // Rücklesen hindurch: Genau hier braucht ihn der Lesepfad, um den
11683
12324
  // Dateipfad `images/<id>.<ext>` zu bilden, statt ihn zu erraten. Nur
11684
12325
  // gesetzt, wenn er im Ereignis steht — ältere Batches tragen ihn nicht.
11685
- ...istText5(b.mime_type) ? { mime_type: b.mime_type } : {},
12326
+ ...istText6(b.mime_type) ? { mime_type: b.mime_type } : {},
11686
12327
  model: b.model ?? null,
11687
12328
  seed: b.seed ?? null,
11688
12329
  width: b.width ?? null,
@@ -11694,7 +12335,7 @@ function collectImageBatches(events) {
11694
12335
  for (const event of events) {
11695
12336
  if (event.type !== SZENEN_EVENT_TYPES.imageBatchPersisted) continue;
11696
12337
  const payload = event.payload;
11697
- if (!payload || !istText5(payload.item_id) || !istText5(payload.prompt_run_id) || !istText5(payload.generation_batch_id)) continue;
12338
+ if (!payload || !istText6(payload.item_id) || !istText6(payload.prompt_run_id) || !istText6(payload.generation_batch_id)) continue;
11698
12339
  if (payload.source_kind !== "generated_in_app" && payload.source_kind !== "external_import") continue;
11699
12340
  const bestehend = byItemId.get(payload.item_id);
11700
12341
  if (bestehend?.generation_batch_ids.includes(payload.generation_batch_id)) continue;
@@ -11705,7 +12346,7 @@ function collectImageBatches(events) {
11705
12346
  prompt_run_id: payload.prompt_run_id,
11706
12347
  generation_batch_ids: [payload.generation_batch_id],
11707
12348
  source_kind: payload.source_kind,
11708
- title: istText5(payload.title) ? payload.title : `Batch aus Lauf ${payload.prompt_run_id}`,
12349
+ title: istText6(payload.title) ? payload.title : `Batch aus Lauf ${payload.prompt_run_id}`,
11709
12350
  images: bilder
11710
12351
  });
11711
12352
  continue;
@@ -11980,7 +12621,7 @@ function createFlowSzenenViewPort(options) {
11980
12621
  ...options.now ? { now: options.now } : {}
11981
12622
  }) : void 0;
11982
12623
  const bildProvider = options.imageProvider ?? (options.generateImage ? createFlowImageProvider(options.generateImage) : void 0);
11983
- const bildFaehigkeit = options.imageCapability ?? { environment_id: "flow", execution_paths: [FLOW_EXECUTION_PATH] };
12624
+ const bildFaehigkeit = options.imageCapability ?? { environment_id: "flow", execution_paths: [{ execution_path: FLOW_EXECUTION_PATH, provider: "google" }] };
11984
12625
  const imageGeneration = bildProvider && imageBatchWrite ? createImageGenerationPort({
11985
12626
  runs: { async getRun(runId) {
11986
12627
  return runs.getRun(runId);
@@ -12132,43 +12773,85 @@ var FAILURE_CLASSES = [
12132
12773
  ];
12133
12774
  var PFLICHTFELDER = [
12134
12775
  "run_id",
12135
- "shot_version_id",
12136
- "shot_element_id",
12137
- "scene_setup_version_id",
12138
- "camera_id",
12139
- "target_model_version_id",
12140
12776
  "provider",
12141
12777
  "model_id",
12142
12778
  "system_prompt",
12143
12779
  "created_at"
12144
12780
  ];
12145
- function istText6(wert) {
12781
+ var TEXTFELDER = [
12782
+ "shot_version_id",
12783
+ "shot_element_id",
12784
+ "scene_setup_version_id",
12785
+ "camera_id",
12786
+ "target_model_version_id"
12787
+ ];
12788
+ var PFLICHT_JE_HERKUNFT = {
12789
+ published: ["shot_version_id", "shot_element_id", "scene_setup_version_id"],
12790
+ draft_chain: ["shot_element_id"],
12791
+ scene_direct: []
12792
+ };
12793
+ var VERBOTEN_JE_HERKUNFT = {
12794
+ published: [],
12795
+ draft_chain: ["shot_version_id", "scene_setup_version_id"],
12796
+ scene_direct: ["shot_version_id", "shot_element_id", "scene_setup_version_id", "camera_id"]
12797
+ };
12798
+ function istText7(wert) {
12146
12799
  return typeof wert === "string" && wert.trim().length > 0;
12147
12800
  }
12148
- function isObject11(wert) {
12801
+ function isObject12(wert) {
12149
12802
  return typeof wert === "object" && wert !== null && !Array.isArray(wert);
12150
12803
  }
12151
- var VERSIONSFELDER = ["shot_version_id", "scene_setup_version_id"];
12152
12804
  var KETTEN_TYPEN = ["scene", "scene_setup", "shot"];
12805
+ var HERKUENFTE = ["published", "draft_chain", "scene_direct"];
12153
12806
  function pruefeLaufherkunft(quelle) {
12154
- if (!isObject11(quelle)) {
12807
+ if (!isObject12(quelle)) {
12155
12808
  return { ok: false, message: '"source" muss ein Objekt sein.' };
12156
12809
  }
12810
+ if (!HERKUENFTE.includes(quelle.kind)) {
12811
+ return {
12812
+ ok: false,
12813
+ message: `"source.kind" ist unbekannt: ${JSON.stringify(quelle.kind)}. Erlaubt: ${HERKUENFTE.join(", ")}.`
12814
+ };
12815
+ }
12157
12816
  if (quelle.kind === "published") {
12158
- for (const feld of VERSIONSFELDER) {
12159
- if (!istText6(quelle[feld])) {
12817
+ for (const feld of ["shot_version_id", "scene_setup_version_id"]) {
12818
+ if (!istText7(quelle[feld])) {
12160
12819
  return { ok: false, message: `"source.${feld}" fehlt oder ist leer.` };
12161
12820
  }
12162
12821
  }
12163
12822
  return { ok: true };
12164
12823
  }
12165
- if (quelle.kind !== "draft_chain") {
12166
- return {
12167
- ok: false,
12168
- message: `"source.kind" ist unbekannt: ${JSON.stringify(quelle.kind)}. Erlaubt: published, draft_chain.`
12169
- };
12824
+ if (quelle.kind === "scene_direct") {
12825
+ const szene = quelle.scene;
12826
+ if (!isObject12(szene)) {
12827
+ return { ok: false, message: '"source.scene" muss ein Objekt sein.' };
12828
+ }
12829
+ if (!istText7(szene.element_id)) {
12830
+ return { ok: false, message: '"source.scene.element_id" fehlt oder ist leer.' };
12831
+ }
12832
+ const ausEntwurf = istText7(szene.draft_id);
12833
+ const ausVersion = istText7(szene.version_id);
12834
+ if (ausEntwurf === ausVersion) {
12835
+ return {
12836
+ ok: false,
12837
+ message: ausEntwurf ? '"source.scene" nennt draft_id und version_id zugleich. Eingefroren wurde genau ein Stand (D-135).' : '"source.scene" nennt weder draft_id noch version_id. Ohne den eingefrorenen Stand ist der Lauf nicht nachvollziehbar (D-97).'
12838
+ };
12839
+ }
12840
+ if (ausEntwurf && (typeof szene.revision !== "number" || !Number.isInteger(szene.revision))) {
12841
+ return {
12842
+ ok: false,
12843
+ message: '"source.scene.revision" muss eine ganze Zahl sein \u2014 ohne sie ist der eingefrorene Entwurfsstand nicht benennbar (D-97).'
12844
+ };
12845
+ }
12846
+ if (ausVersion && szene.revision !== null && szene.revision !== void 0) {
12847
+ return {
12848
+ ok: false,
12849
+ message: '"source.scene.revision" ist bei einer veroeffentlichten Version gesetzt. Eine Version ist unveraenderlich und hat keine Revision (D-02).'
12850
+ };
12851
+ }
12852
+ return { ok: true };
12170
12853
  }
12171
- if (!istText6(quelle.chain_id)) {
12854
+ if (!istText7(quelle.chain_id)) {
12172
12855
  return { ok: false, message: '"source.chain_id" fehlt oder ist leer.' };
12173
12856
  }
12174
12857
  if (!Array.isArray(quelle.nodes) || quelle.nodes.length === 0) {
@@ -12178,7 +12861,7 @@ function pruefeLaufherkunft(quelle) {
12178
12861
  };
12179
12862
  }
12180
12863
  for (const [index, knoten] of quelle.nodes.entries()) {
12181
- if (!isObject11(knoten)) {
12864
+ if (!isObject12(knoten)) {
12182
12865
  return { ok: false, message: `"source.nodes[${index}]" ist kein Objekt.` };
12183
12866
  }
12184
12867
  if (!KETTEN_TYPEN.includes(knoten.type)) {
@@ -12187,7 +12870,7 @@ function pruefeLaufherkunft(quelle) {
12187
12870
  message: `"source.nodes[${index}].type" ist unbekannt: ${JSON.stringify(knoten.type)}.`
12188
12871
  };
12189
12872
  }
12190
- if (!istText6(knoten.element_id) || !istText6(knoten.draft_id)) {
12873
+ if (!istText7(knoten.element_id) || !istText7(knoten.draft_id)) {
12191
12874
  return {
12192
12875
  ok: false,
12193
12876
  message: `"source.nodes[${index}]" braucht element_id und draft_id.`
@@ -12200,10 +12883,10 @@ function pruefeLaufherkunft(quelle) {
12200
12883
  };
12201
12884
  }
12202
12885
  }
12203
- if (quelle.derivation_run_id !== void 0 && !istText6(quelle.derivation_run_id)) {
12886
+ if (quelle.derivation_run_id !== void 0 && !istText7(quelle.derivation_run_id)) {
12204
12887
  return { ok: false, message: '"source.derivation_run_id" ist gesetzt, aber leer.' };
12205
12888
  }
12206
- if (quelle.derivation_recovery_id !== void 0 && !istText6(quelle.derivation_recovery_id)) {
12889
+ if (quelle.derivation_recovery_id !== void 0 && !istText7(quelle.derivation_recovery_id)) {
12207
12890
  return { ok: false, message: '"source.derivation_recovery_id" ist gesetzt, aber leer.' };
12208
12891
  }
12209
12892
  return { ok: true };
@@ -12217,25 +12900,38 @@ function checkPromptRunRecord(candidate) {
12217
12900
  }
12218
12901
  const record = candidate;
12219
12902
  const quelle = record.source;
12220
- const ausKette = isObject11(quelle) && quelle.kind === "draft_chain";
12221
12903
  if (quelle !== void 0) {
12222
12904
  const urteil2 = pruefeLaufherkunft(quelle);
12223
12905
  if (!urteil2.ok) return urteil2;
12224
12906
  }
12225
- const pflicht = ausKette ? PFLICHTFELDER.filter((f) => !VERSIONSFELDER.includes(f)) : PFLICHTFELDER;
12226
- for (const feld of pflicht) {
12227
- if (!istText6(record[feld])) {
12907
+ const herkunft = isObject12(quelle) && typeof quelle.kind === "string" ? quelle.kind : "published";
12908
+ for (const feld of PFLICHTFELDER) {
12909
+ if (!istText7(record[feld])) {
12228
12910
  return { ok: false, message: `"${feld}" fehlt oder ist leer.` };
12229
12911
  }
12230
12912
  }
12231
- if (ausKette) {
12232
- for (const feld of VERSIONSFELDER) {
12233
- if (istText6(record[feld])) {
12234
- return {
12235
- ok: false,
12236
- message: `"${feld}" ist bei einem Lauf aus einer Draft-Kette gesetzt. Dort gibt es keine Versionen, und erfundene sind unzulaessig (D-98).`
12237
- };
12238
- }
12913
+ for (const feld of TEXTFELDER) {
12914
+ if (typeof record[feld] !== "string") {
12915
+ return {
12916
+ ok: false,
12917
+ message: `"${feld}" fehlt. Wo es keinen Wert gibt, gehoert eine leere Zeichenkette hin \u2014 kein fehlendes Feld (D-135).`
12918
+ };
12919
+ }
12920
+ }
12921
+ for (const feld of PFLICHT_JE_HERKUNFT[herkunft] ?? []) {
12922
+ if (!istText7(record[feld])) {
12923
+ return {
12924
+ ok: false,
12925
+ message: `"${feld}" fehlt oder ist leer, wird bei Herkunft "${herkunft}" aber gebraucht.`
12926
+ };
12927
+ }
12928
+ }
12929
+ for (const feld of VERBOTEN_JE_HERKUNFT[herkunft] ?? []) {
12930
+ if (istText7(record[feld])) {
12931
+ return {
12932
+ ok: false,
12933
+ message: `"${feld}" ist bei einem Lauf der Herkunft "${herkunft}" gesetzt. Dort gibt es diesen Wert nicht, und erfundene sind unzulaessig (D-98/D-135).`
12934
+ };
12239
12935
  }
12240
12936
  }
12241
12937
  if (record.status !== "succeeded" && record.status !== "failed") {
@@ -12268,7 +12964,7 @@ function checkPromptRunRecord(candidate) {
12268
12964
  message: `"failure.class" ist unbekannt: ${JSON.stringify(failure.class)}. Erlaubt sind ${FAILURE_CLASSES.join(", ")}.`
12269
12965
  };
12270
12966
  }
12271
- if (!istText6(failure.message)) {
12967
+ if (!istText7(failure.message)) {
12272
12968
  return { ok: false, message: '"failure.message" fehlt oder ist leer.' };
12273
12969
  }
12274
12970
  return { ok: true };
@@ -12310,7 +13006,7 @@ function checkSceneDerivationRecord(candidate) {
12310
13006
  }
12311
13007
  const record = candidate;
12312
13008
  for (const feld of DERIVATION_PFLICHTFELDER) {
12313
- if (!istText6(record[feld])) {
13009
+ if (!istText7(record[feld])) {
12314
13010
  return { ok: false, message: `"${feld}" fehlt oder ist leer.` };
12315
13011
  }
12316
13012
  }
@@ -12365,13 +13061,13 @@ function checkSceneDerivationRecord(candidate) {
12365
13061
  return { ok: false, message: '"follows" muss ein Objekt sein.' };
12366
13062
  }
12367
13063
  const f = folgt;
12368
- if (!istText6(f.run_id)) {
13064
+ if (!istText7(f.run_id)) {
12369
13065
  return { ok: false, message: '"follows.run_id" fehlt oder ist leer.' };
12370
13066
  }
12371
13067
  if (f.run_id === record.run_id) {
12372
13068
  return { ok: false, message: '"follows.run_id" zeigt auf den Lauf selbst.' };
12373
13069
  }
12374
- if (!istText6(f.note)) {
13070
+ if (!istText7(f.note)) {
12375
13071
  return {
12376
13072
  ok: false,
12377
13073
  message: '"follows.note" fehlt oder ist leer \u2014 ohne Beanstandung ist ein Folgelauf nicht nachvollziehbar (D-89).'
@@ -12385,7 +13081,7 @@ function checkSceneDerivationRecord(candidate) {
12385
13081
  }
12386
13082
  }
12387
13083
  const reply = record.reply;
12388
- if (reply !== void 0 && !istText6(reply)) {
13084
+ if (reply !== void 0 && !istText7(reply)) {
12389
13085
  return {
12390
13086
  ok: false,
12391
13087
  message: `"reply" ist unbrauchbar: erwartet wird eine nicht leere Zeichenkette, angekommen ist ${JSON.stringify(reply)}. Ohne "reply" einreichen ist zulaessig.`
@@ -12405,7 +13101,7 @@ function checkSceneDerivationRecord(candidate) {
12405
13101
  message: `"failure.class" ist unbekannt: ${JSON.stringify(failure.class)}. Erlaubt sind ${FAILURE_CLASSES.join(", ")}.`
12406
13102
  };
12407
13103
  }
12408
- if (!istText6(failure.message)) {
13104
+ if (!istText7(failure.message)) {
12409
13105
  return { ok: false, message: '"failure.message" fehlt oder ist leer.' };
12410
13106
  }
12411
13107
  if (Array.isArray(record.proposals) && record.proposals.length > 0) {
@@ -12460,7 +13156,7 @@ function checkSceneDerivationRecord(candidate) {
12460
13156
  };
12461
13157
  }
12462
13158
  for (const [gapIndex, luecke] of gaps.entries()) {
12463
- if (!luecke || typeof luecke !== "object" || !istText6(luecke.pointer) || !istText6(luecke.reason)) {
13159
+ if (!luecke || typeof luecke !== "object" || !istText7(luecke.pointer) || !istText7(luecke.reason)) {
12464
13160
  return {
12465
13161
  ok: false,
12466
13162
  message: `"proposals[${index}].gaps[${gapIndex}]" braucht pointer und reason.`
@@ -12486,7 +13182,7 @@ function checkSceneDerivationRecoveryRecord(candidate) {
12486
13182
  }
12487
13183
  const record = candidate;
12488
13184
  for (const feld of ["recovery_id", "run_id", "created_at"]) {
12489
- if (!istText6(record[feld])) {
13185
+ if (!istText7(record[feld])) {
12490
13186
  return { ok: false, message: `"${feld}" fehlt oder ist leer.` };
12491
13187
  }
12492
13188
  }
@@ -12513,7 +13209,7 @@ function checkSceneDerivationRecoveryRecord(candidate) {
12513
13209
  return { ok: false, message: '"diagnostics" muss ein Array sein (auch ein leeres).' };
12514
13210
  }
12515
13211
  for (const [index, befund] of record.diagnostics.entries()) {
12516
- if (!befund || typeof befund !== "object" || !istText6(befund.code) || !istText6(befund.message)) {
13212
+ if (!befund || typeof befund !== "object" || !istText7(befund.code) || !istText7(befund.message)) {
12517
13213
  return {
12518
13214
  ok: false,
12519
13215
  message: `"diagnostics[${index}]" braucht code und message.`
@@ -12565,7 +13261,7 @@ function checkSceneDerivationRecoveryRecord(candidate) {
12565
13261
  }
12566
13262
  if (Array.isArray(gaps)) {
12567
13263
  for (const [gapIndex, luecke] of gaps.entries()) {
12568
- if (!luecke || typeof luecke !== "object" || !istText6(luecke.pointer) || !istText6(luecke.reason)) {
13264
+ if (!luecke || typeof luecke !== "object" || !istText7(luecke.pointer) || !istText7(luecke.reason)) {
12569
13265
  return {
12570
13266
  ok: false,
12571
13267
  message: `"proposals[${index}].gaps[${gapIndex}]" braucht pointer und reason.`
@@ -12602,9 +13298,15 @@ function checkSceneDerivationRecoveryRecord(candidate) {
12602
13298
  }
12603
13299
 
12604
13300
  // src/features/szenen/SzenenView.tsx
12605
- var import_react15 = require("react");
13301
+ var import_react16 = require("react");
12606
13302
 
12607
13303
  // src/features/szenen/szenenViewModel.ts
13304
+ var KEINE_BAUSTEINE = [
13305
+ "scene",
13306
+ "scene_setup",
13307
+ "shot"
13308
+ ];
13309
+ var BAUSTEIN_TYPES = SZENEN_ELEMENT_TYPES.filter((typ) => !KEINE_BAUSTEINE.includes(typ));
12608
13310
  var ALLE_BEREICHE = [
12609
13311
  {
12610
13312
  id: "derive",
@@ -12689,7 +13391,7 @@ function noticeFor(ergebnis, was) {
12689
13391
  }
12690
13392
 
12691
13393
  // src/features/szenen/areas/ElementsArea.tsx
12692
- var import_react10 = require("react");
13394
+ var import_react11 = require("react");
12693
13395
 
12694
13396
  // src/features/szenen/areas/usePortQuery.ts
12695
13397
  var import_react = require("react");
@@ -12723,6 +13425,32 @@ function usePortQuery(frage, abhaengigkeiten) {
12723
13425
  // src/features/szenen/areas/ElementDetail.tsx
12724
13426
  var import_react9 = require("react");
12725
13427
 
13428
+ // src/features/szenen/elementLabels.ts
13429
+ var LABELS = {
13430
+ scene_component: { singular: "Szenenbaustein", plural: "Szenenbausteine" },
13431
+ scene: { singular: "Szene", plural: "Szenen" },
13432
+ shot_concept: { singular: "Prompt-Idee", plural: "Prompt-Ideen" },
13433
+ camera_preset: { singular: "Kamera", plural: "Kameras" },
13434
+ camera_pattern: { singular: "Kamera-Muster", plural: "Kamera-Muster" },
13435
+ style: { singular: "Stil", plural: "Stile" },
13436
+ scene_setup: { singular: "Bildaufbau", plural: "Bildaufbauten" },
13437
+ shot: { singular: "Prompt", plural: "Prompts" },
13438
+ prompt_policy: { singular: "Prompt-Regel", plural: "Prompt-Regeln" },
13439
+ prompt_fragment: { singular: "Prompt-Baustein", plural: "Prompt-Bausteine" },
13440
+ target_model: { singular: "Zielmodell", plural: "Zielmodelle" },
13441
+ sequence: { singular: "Sequenz", plural: "Sequenzen" },
13442
+ scene_derivation_policy: {
13443
+ singular: "Rekonstruktions-Regel",
13444
+ plural: "Rekonstruktions-Regeln"
13445
+ }
13446
+ };
13447
+ function elementTypLabel(typ) {
13448
+ return LABELS[typ]?.singular ?? typ;
13449
+ }
13450
+ function elementTypPlural(typ) {
13451
+ return LABELS[typ]?.plural ?? typ;
13452
+ }
13453
+
12726
13454
  // src/features/szenen/schemaForm.ts
12727
13455
  var FORM_JE_REF = {
12728
13456
  "common.schema.json#/$defs/slug": "slug",
@@ -13018,7 +13746,7 @@ var SEMANTIK = {
13018
13746
  function feldSemantik(type, pfad) {
13019
13747
  return SEMANTIK[`${type}.${pfad}`] ?? null;
13020
13748
  }
13021
- var LABELS = {
13749
+ var LABELS2 = {
13022
13750
  key: "Kennung",
13023
13751
  name: "Name",
13024
13752
  text: "Text",
@@ -13063,13 +13791,13 @@ var LABELS = {
13063
13791
  properties: "Zusatzangaben"
13064
13792
  };
13065
13793
  function feldLabel(type, pfad, name) {
13066
- return feldSemantik(type, pfad)?.label ?? LABELS[name] ?? name;
13794
+ return feldSemantik(type, pfad)?.label ?? LABELS2[name] ?? name;
13067
13795
  }
13068
13796
 
13069
13797
  // src/features/szenen/areas/SchemaFields.tsx
13070
13798
  var import_jsx_runtime = require("react/jsx-runtime");
13071
- var isObject12 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
13072
- var istVersionRef = (v) => isObject12(v) && typeof v.element_id === "string" && typeof v.version_id === "string";
13799
+ var isObject13 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
13800
+ var istVersionRef = (v) => isObject13(v) && typeof v.element_id === "string" && typeof v.version_id === "string";
13073
13801
  function leseJson(wert) {
13074
13802
  if (!wert || wert === NULL_MARKER) return null;
13075
13803
  try {
@@ -13297,13 +14025,13 @@ var VersionRefListeFeld = ({ port, kontextkette, feld, wert, onChange, readOnly,
13297
14025
  }
13298
14026
  const schreiben = (neu) => onChange(
13299
14027
  feld.path,
13300
- schreibListe(neu.map((eintrag, i) => isObject12(eintrag) && mitRolle ? { ...eintrag, rank: i } : eintrag))
14028
+ schreibListe(neu.map((eintrag, i) => isObject13(eintrag) && mitRolle ? { ...eintrag, rank: i } : eintrag))
13301
14029
  );
13302
14030
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "szenen-feld__reflist", "data-testid": `reflist-${feld.path}`, children: [
13303
14031
  liste.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { "data-testid": `reflist-${feld.path}-leer`, children: "Keine Eintr\xE4ge." }),
13304
14032
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { children: liste.map((eintrag, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { "data-testid": `reflist-${feld.path}-${index}`, children: [
13305
14033
  istVersionRef(eintrag) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefAnzeige, { port, ref_: eintrag, testId: `reflist-${feld.path}-${index}-ref` }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: JSON.stringify(eintrag) }),
13306
- mitRolle === "styleRole" && isObject12(eintrag) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
14034
+ mitRolle === "styleRole" && isObject13(eintrag) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
13307
14035
  "select",
13308
14036
  {
13309
14037
  "data-testid": `reflist-${feld.path}-${index}-role`,
@@ -13316,7 +14044,7 @@ var VersionRefListeFeld = ({ port, kontextkette, feld, wert, onChange, readOnly,
13316
14044
  ]
13317
14045
  }
13318
14046
  ),
13319
- mitRolle === "frei" && isObject12(eintrag) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
14047
+ mitRolle === "frei" && isObject13(eintrag) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
13320
14048
  "input",
13321
14049
  {
13322
14050
  "data-testid": `reflist-${feld.path}-${index}-role`,
@@ -13326,7 +14054,7 @@ var VersionRefListeFeld = ({ port, kontextkette, feld, wert, onChange, readOnly,
13326
14054
  onChange: (e) => schreiben(liste.map((x, i) => i === index ? { ...x, role: e.target.value } : x))
13327
14055
  }
13328
14056
  ),
13329
- mitGewicht && isObject12(eintrag) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
14057
+ mitGewicht && isObject13(eintrag) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
13330
14058
  "input",
13331
14059
  {
13332
14060
  "data-testid": `reflist-${feld.path}-${index}-weight`,
@@ -13557,7 +14285,7 @@ var KameraFeld = ({
13557
14285
  if (phase.status !== "ready" || !phase.value) return [];
13558
14286
  const cameras = valueAtPath(phase.value.payload, "camera_rig.cameras");
13559
14287
  if (!Array.isArray(cameras)) return [];
13560
- return cameras.filter(isObject12).map((c) => ({
14288
+ return cameras.filter(isObject13).map((c) => ({
13561
14289
  id: typeof c.camera_id === "string" ? c.camera_id : null,
13562
14290
  name: typeof c.name === "string" ? c.name : null
13563
14291
  })).filter((c) => c.id !== null);
@@ -13702,11 +14430,11 @@ var MediaRefListeFeld = ({ feld, wert, onChange, readOnly }) => {
13702
14430
  }
13703
14431
  const schreiben = (neu) => onChange(
13704
14432
  feld.path,
13705
- schreibListe(neu.map((e, i) => isObject12(e) ? { ...e, position: i } : e))
14433
+ schreibListe(neu.map((e, i) => isObject13(e) ? { ...e, position: i } : e))
13706
14434
  );
13707
14435
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "szenen-feld__liste", "data-testid": `feld-${feld.path}`, children: [
13708
14436
  liste.map((eintrag, index) => {
13709
- const objekt = isObject12(eintrag) ? eintrag : {};
14437
+ const objekt = isObject13(eintrag) ? eintrag : {};
13710
14438
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "szenen-feld__liste-zeile", children: [
13711
14439
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
13712
14440
  "input",
@@ -13715,7 +14443,7 @@ var MediaRefListeFeld = ({ feld, wert, onChange, readOnly }) => {
13715
14443
  value: typeof objekt.asset_id === "string" ? objekt.asset_id : "",
13716
14444
  readOnly,
13717
14445
  placeholder: "asset_id (UUID)",
13718
- onChange: (e) => schreiben(liste.map((x, i) => i === index ? { ...isObject12(x) ? x : {}, asset_id: e.target.value } : x))
14446
+ onChange: (e) => schreiben(liste.map((x, i) => i === index ? { ...isObject13(x) ? x : {}, asset_id: e.target.value } : x))
13719
14447
  }
13720
14448
  ),
13721
14449
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
@@ -13724,7 +14452,7 @@ var MediaRefListeFeld = ({ feld, wert, onChange, readOnly }) => {
13724
14452
  "data-testid": `feld-${feld.path}-${index}-rolle`,
13725
14453
  value: typeof objekt.role === "string" ? objekt.role : "",
13726
14454
  disabled: readOnly,
13727
- onChange: (e) => schreiben(liste.map((x, i) => i === index ? { ...isObject12(x) ? x : {}, role: e.target.value } : x)),
14455
+ onChange: (e) => schreiben(liste.map((x, i) => i === index ? { ...isObject13(x) ? x : {}, role: e.target.value } : x)),
13728
14456
  children: [
13729
14457
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "(Rolle w\xE4hlen)" }),
13730
14458
  rollen.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: r, children: r }, r))
@@ -13767,9 +14495,10 @@ var LEERES_PROFIL = {
13767
14495
  var listeAus = (text) => text.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
13768
14496
  var AusfuehrungsprofileFeld = ({ feld, wert, onChange, readOnly }) => {
13769
14497
  const gelesen = leseListe(wert);
13770
- const profile = (gelesen ?? []).filter(isObject12);
14498
+ const profile = (gelesen ?? []).filter(isObject13);
13771
14499
  const unlesbar = gelesen === null;
13772
14500
  const schreibe = (neu) => onChange(feld.path, schreibListe(neu));
14501
+ const alleBefunde = checkImageExecutionProfiles(profile);
13773
14502
  const aendere = (index, patch) => schreibe(profile.map((p, i) => i === index ? { ...p, ...patch } : p));
13774
14503
  if (unlesbar) {
13775
14504
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", "data-testid": `feld-${feld.path}-unlesbar`, children: "Der gespeicherte Wert ist keine Profilliste. Er bleibt unver\xE4ndert stehen; bitte an der Quelle korrigieren." });
@@ -13777,7 +14506,7 @@ var AusfuehrungsprofileFeld = ({ feld, wert, onChange, readOnly }) => {
13777
14506
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "szenen-feld__profile", "data-testid": `feld-${feld.path}`, children: [
13778
14507
  profile.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { "data-testid": `feld-${feld.path}-keine`, children: "Dieses Zielmodell wird f\xFCr die Prompt-Optimierung verwendet und ist derzeit nicht direkt aus der App aufrufbar." }),
13779
14508
  profile.map((profil, index) => {
13780
- const befunde = checkImageExecutionProfile(profil);
14509
+ const befunde = alleBefunde[index] ?? [];
13781
14510
  const text = (schluessel) => typeof profil[schluessel] === "string" ? profil[schluessel] : "";
13782
14511
  const liste = (schluessel) => Array.isArray(profil[schluessel]) ? profil[schluessel].join(", ") : "";
13783
14512
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("fieldset", { "data-testid": `profil-${index}`, className: "szenen-feld__profil", children: [
@@ -14528,60 +15257,72 @@ var CapabilityPanel = ({ port, elementId, setupPayload }) => {
14528
15257
  ] });
14529
15258
  };
14530
15259
 
14531
- // src/features/szenen/areas/ChainPromptAction.tsx
15260
+ // src/features/szenen/areas/PromptStartAction.tsx
14532
15261
  var import_react6 = require("react");
14533
15262
  var import_jsx_runtime5 = require("react/jsx-runtime");
14534
- var ChainPromptAction = ({
15263
+ var PromptStartAction = ({
14535
15264
  port,
14536
- shotElementId
15265
+ source,
15266
+ hinweise = [],
15267
+ blocker = null,
15268
+ onLauf
14537
15269
  }) => {
14538
15270
  const [lauf, setLauf] = (0, import_react6.useState)(null);
14539
15271
  const [meldung, setMeldung] = (0, import_react6.useState)(null);
14540
15272
  const [ausgang, setAusgang] = (0, import_react6.useState)(null);
14541
15273
  const [laeuft, setLaeuft] = (0, import_react6.useState)(false);
14542
15274
  const runs = port.runs;
15275
+ const ausKette = source.kind === "draft_chain";
15276
+ const id = (name) => ausKette ? `kette-${name}` : `szene-${name}`;
14543
15277
  async function erzeugen() {
14544
15278
  setLaeuft(true);
14545
15279
  setMeldung(null);
14546
15280
  setAusgang(null);
14547
15281
  try {
14548
- const ergebnis = await runs.startRunFromDraft({ shotElementId });
15282
+ const ergebnis = source.kind === "draft_chain" ? await runs.startRunFromDraft({ shotElementId: source.shotElementId }) : await runs.startRunFromScene({ sceneElementId: source.sceneElementId });
14549
15283
  if (ergebnis.kind !== "ok") {
14550
15284
  setMeldung(ergebnis.kind === "unsupported" ? `Dieser Host kann "${ergebnis.capability}" nicht.` : ergebnis.message);
14551
15285
  setAusgang(ergebnis.kind === "unsupported" ? "error" : ergebnis.kind);
14552
15286
  return;
14553
15287
  }
14554
15288
  setLauf(ergebnis.value);
15289
+ onLauf?.();
14555
15290
  } finally {
14556
15291
  setLaeuft(false);
14557
15292
  }
14558
15293
  }
14559
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "szenen-kette", "data-testid": "kette-prompt-aktion", children: [
14560
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h5", { children: "Prompt aus der Draft-Kette" }),
14561
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "szenen-area__lead", children: [
15294
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "szenen-kette", "data-testid": id("prompt-aktion"), children: [
15295
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h5", { children: ausKette ? "Prompt aus der Draft-Kette" : "Prompt aus dieser Szene" }),
15296
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "szenen-area__lead", children: ausKette ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
14562
15297
  "Dieser Shot geh\xF6rt zu einer Draft-Kette. Der Lauf friert Szene, Aufbau und Shot in dem Stand ein, den er gerade vorfindet \u2014",
14563
15298
  " ",
14564
15299
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "ohne" }),
14565
15300
  " dass etwas ver\xF6ffentlicht werden muss."
14566
- ] }),
15301
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
15302
+ "Der Lauf friert diese Szene in dem Stand ein, den er gerade vorfindet. Bildaufbau, Kamera und Zielmodell sind ",
15303
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "nicht n\xF6tig" }),
15304
+ " \u2014 was fehlt, wird weggelassen und am Lauf festgehalten, nicht erg\xE4nzt."
15305
+ ] }) }),
15306
+ hinweise.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "szenen-detail__hint", "data-testid": id("hinweise"), role: "status", children: hinweise.map((hinweis, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: hinweis }, i)) }),
15307
+ blocker && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "szenen-error", role: "alert", "data-testid": id("blocker"), children: blocker }),
14567
15308
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
14568
15309
  "button",
14569
15310
  {
14570
15311
  type: "button",
14571
- disabled: laeuft,
15312
+ disabled: laeuft || blocker !== null,
14572
15313
  onClick: () => void erzeugen(),
14573
- "data-testid": "kette-prompt",
14574
- children: laeuft ? "Pr\xFCft und erzeugt \u2026" : "Draft-Kette pr\xFCfen und Prompt erzeugen (kostet einen Modellaufruf)"
15314
+ "data-testid": id("prompt"),
15315
+ children: laeuft ? "Pr\xFCft und erzeugt \u2026" : ausKette ? "Draft-Kette pr\xFCfen und Prompt erzeugen (kostet einen Modellaufruf)" : "Prompt erzeugen (kostet einen Modellaufruf)"
14575
15316
  }
14576
15317
  ),
14577
- meldung && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "szenen-error", role: "alert", "data-testid": "kette-meldung", children: [
15318
+ meldung && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "szenen-error", role: "alert", "data-testid": id("meldung"), children: [
14578
15319
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: meldung }),
14579
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { "data-testid": "kette-kein-modell", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Es wurde kein Modell gerufen." }) }),
14580
- ausgang === "conflict" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { "data-testid": "kette-konflikt", children: "Ein Entwurf der Kette wurde zwischenzeitlich ge\xE4ndert. Ein erneuter Versuch friert den aktuellen Stand ein." }),
14581
- ausgang === "rejected" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { "data-testid": "kette-mangel", children: "Die Kette selbst ist noch nicht vollst\xE4ndig. Ein erneuter Versuch \xE4ndert daran nichts \u2014 die Entw\xFCrfe m\xFCssen zuerst erg\xE4nzt werden." }),
14582
- ausgang === "error" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { "data-testid": "kette-technisch", children: "Das war ein technisches Problem beim Zugriff, kein Mangel der Kette. Ein erneuter Versuch ist sinnvoll." })
15320
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { "data-testid": id("kein-modell"), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Es wurde kein Modell gerufen." }) }),
15321
+ ausgang === "conflict" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { "data-testid": id("konflikt"), children: ausKette ? "Ein Entwurf der Kette wurde zwischenzeitlich ge\xE4ndert. Ein erneuter Versuch friert den aktuellen Stand ein." : "Die Szene wurde zwischenzeitlich ge\xE4ndert. Ein erneuter Versuch friert den aktuellen Stand ein." }),
15322
+ ausgang === "rejected" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { "data-testid": id("mangel"), children: ausKette ? "Die Kette selbst ist noch nicht vollst\xE4ndig. Ein erneuter Versuch \xE4ndert daran nichts \u2014 die Entw\xFCrfe m\xFCssen zuerst erg\xE4nzt werden." : "Aus diesem Stand l\xE4sst sich kein Auftrag herstellen. Ein erneuter Versuch \xE4ndert daran nichts \u2014 die Szene muss zuerst Inhalt bekommen." }),
15323
+ ausgang === "error" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { "data-testid": id("technisch"), children: "Das war ein technisches Problem beim Zugriff, kein fachlicher Mangel. Ein erneuter Versuch ist sinnvoll." })
14583
15324
  ] }),
14584
- lauf && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "szenen-run", "data-testid": "kette-lauf", children: [
15325
+ lauf && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "szenen-run", "data-testid": id("lauf"), children: [
14585
15326
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h5", { children: [
14586
15327
  "Prompt-Lauf ",
14587
15328
  lauf.status === "succeeded" ? "gelungen" : "gescheitert"
@@ -14593,7 +15334,7 @@ var ChainPromptAction = ({
14593
15334
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: lauf.model_id }),
14594
15335
  "."
14595
15336
  ] }),
14596
- lauf.status === "succeeded" && lauf.output && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("pre", { className: "szenen-proposal__payload", "data-testid": "kette-prompt-text", children: lauf.output.positive }),
15337
+ lauf.status === "succeeded" && lauf.output && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("pre", { className: "szenen-proposal__payload", "data-testid": id("prompt-text"), children: lauf.output.positive }),
14597
15338
  lauf.status === "failed" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "szenen-error", children: [
14598
15339
  lauf.failure?.class,
14599
15340
  " \u2014 ",
@@ -14763,12 +15504,27 @@ var RunImagesPanel = ({ port, lauf }) => {
14763
15504
  "Lauf ",
14764
15505
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { "data-testid": `eingang-lauf-${lauf.run_id}`, children: lauf.run_id })
14765
15506
  ] }),
14766
- quelle.kind === "published" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { "data-testid": `eingang-herkunft-${lauf.run_id}`, children: [
15507
+ quelle.kind === "published" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { "data-testid": `eingang-herkunft-${lauf.run_id}`, children: [
14767
15508
  "ver\xF6ffentlichte Shot-Version ",
14768
15509
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: quelle.shot_version_id })
14769
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { "data-testid": `eingang-herkunft-${lauf.run_id}`, children: [
15510
+ ] }),
15511
+ quelle.kind === "draft_chain" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { "data-testid": `eingang-herkunft-${lauf.run_id}`, children: [
14770
15512
  "Draft-Kette ",
14771
15513
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: quelle.chain_id })
15514
+ ] }),
15515
+ quelle.kind === "scene_direct" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { "data-testid": `eingang-herkunft-${lauf.run_id}`, children: [
15516
+ "Szene ",
15517
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: quelle.scene.element_id }),
15518
+ quelle.scene.draft_id ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
15519
+ " \xB7 Entwurf ",
15520
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: quelle.scene.draft_id }),
15521
+ " (Revision ",
15522
+ quelle.scene.revision,
15523
+ ")"
15524
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
15525
+ " \xB7 Version ",
15526
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: quelle.scene.version_id })
15527
+ ] })
14772
15528
  ] })
14773
15529
  ] }),
14774
15530
  quelle.kind === "draft_chain" && quelle.derivation_run_id ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -15334,9 +16090,13 @@ var RunsPanel = ({ port, source, contextId }) => {
15334
16090
  const [notiz, setNotiz] = (0, import_react8.useState)(null);
15335
16091
  const [nachladen, setNachladen] = (0, import_react8.useState)(0);
15336
16092
  const faehig = capabilitiesOf(port);
15337
- const quellSchluessel = source.kind === "published" ? source.shotVersionId : source.chainId;
16093
+ const quellSchluessel = source.kind === "published" ? source.shotVersionId : source.kind === "draft_chain" ? source.chainId : source.sceneElementId;
15338
16094
  const [phase, neuLaden] = usePortQuery(
15339
- () => source.kind === "published" ? port.runs.listRunsForShot(source.shotVersionId) : port.runs.listRunsForChain(source.chainId),
16095
+ () => {
16096
+ if (source.kind === "published") return port.runs.listRunsForShot(source.shotVersionId);
16097
+ if (source.kind === "draft_chain") return port.runs.listRunsForChain(source.chainId);
16098
+ return port.runs.listRunsForScene(source.sceneElementId);
16099
+ },
15340
16100
  [port, source.kind, quellSchluessel, nachladen]
15341
16101
  );
15342
16102
  const starten = async () => {
@@ -15375,7 +16135,7 @@ var RunsPanel = ({ port, source, contextId }) => {
15375
16135
  "L\xE4ufe konnten nicht geladen werden: ",
15376
16136
  phase.message
15377
16137
  ] }),
15378
- phase.status === "ready" && laeufe.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { "data-testid": "keine-laeufe", children: source.kind === "published" ? "F\xFCr diese Shot-Version gibt es noch keinen Lauf." : "F\xFCr diese Draft-Kette gibt es noch keinen Lauf." }),
16138
+ phase.status === "ready" && laeufe.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { "data-testid": "keine-laeufe", children: source.kind === "published" ? "F\xFCr diese Shot-Version gibt es noch keinen Lauf." : source.kind === "draft_chain" ? "F\xFCr diese Draft-Kette gibt es noch keinen Lauf." : "F\xFCr diese Szene gibt es noch keinen direkten Lauf." }),
15379
16139
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ol", { "data-testid": "runden-liste", children: laeufe.map((lauf) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
15380
16140
  RundenEintrag,
15381
16141
  {
@@ -15580,6 +16340,23 @@ var ElementDetail = ({
15580
16340
  if (!kette2) return null;
15581
16341
  return kette2.links[0]?.field ?? null;
15582
16342
  }, [schnappschuss?.draft?.chain]);
16343
+ const laufStand = (0, import_react9.useMemo)(() => {
16344
+ if (!schnappschuss || schnappschuss.element.type !== "scene") return null;
16345
+ if (schnappschuss.draft) return schnappschuss.draft.payload;
16346
+ const kopf = usableHeadVersionId(kopfAufloesung);
16347
+ if (!kopf) return null;
16348
+ return schnappschuss.versions.find((v) => v.version_id === kopf)?.payload ?? null;
16349
+ }, [schnappschuss, kopfAufloesung]);
16350
+ const szenenBlocker = (0, import_react9.useMemo)(() => {
16351
+ if (!schnappschuss || schnappschuss.element.type !== "scene") return null;
16352
+ if (laufStand === null) {
16353
+ return schnappschuss.versions.length > 0 ? "Diese Szene hat keinen Entwurf und in diesem Kontext keinen bevorzugten Kopf. Welcher Stand gilt, entscheidet keine Reihenfolge (D-36) \u2014 bitte oben eine Version als bevorzugt setzen." : "Diese Szene hat noch keinen gespeicherten Stand. Ein Lauf friert ein, was gespeichert ist \u2014 bitte zuerst den Entwurf speichern.";
16354
+ }
16355
+ const flag = sceneOnlyCapabilities(laufStand).can_render_prompt;
16356
+ if (flag.state === "yes") return null;
16357
+ const grund = flag.reasons[0];
16358
+ return grund && "message" in grund ? grund.message : "Kein Lauf moeglich.";
16359
+ }, [schnappschuss, laufStand]);
15583
16360
  const vorschau = (0, import_react9.useMemo)(() => {
15584
16361
  if (!schnappschuss) return null;
15585
16362
  try {
@@ -15713,8 +16490,7 @@ var ElementDetail = ({
15713
16490
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("header", { children: [
15714
16491
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { children: schnappschuss.metadata?.title ?? "(ohne Titel)" }),
15715
16492
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("p", { className: "szenen-detail__ids", children: [
15716
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: typ }),
15717
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { children: schnappschuss.element.element_id }),
16493
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-testid": "element-typ", children: elementTypLabel(typ) }),
15718
16494
  schnappschuss.element.retired && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-testid": "ist-stillgelegt", children: "stillgelegt" })
15719
16495
  ] })
15720
16496
  ] }),
@@ -15892,10 +16668,13 @@ var ElementDetail = ({
15892
16668
  // voraus" gilt nur noch fuer den Einzel-Shot.
15893
16669
  draft?.chain ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
15894
16670
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
15895
- ChainPromptAction,
16671
+ PromptStartAction,
15896
16672
  {
15897
16673
  port,
15898
- shotElementId: schnappschuss.element.element_id
16674
+ source: {
16675
+ kind: "draft_chain",
16676
+ shotElementId: schnappschuss.element.element_id
16677
+ }
15899
16678
  }
15900
16679
  ),
15901
16680
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
@@ -15915,6 +16694,30 @@ var ElementDetail = ({
15915
16694
  source: { kind: "published", shotVersionId: laufVersionId }
15916
16695
  }
15917
16696
  ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { "data-testid": "laufquelle-unklar", children: "Dieser Shot hat mehrere ver\xF6ffentlichte Versionen und keinen bevorzugten Kopf in diesem Kontext. Welche davon einen Lauf tr\xE4gt, entscheidet keine Reihenfolge \u2014 bitte oben eine Version anzeigen oder als bevorzugt setzen." })),
16697
+ typ === "scene" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
16698
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
16699
+ PromptStartAction,
16700
+ {
16701
+ port,
16702
+ source: { kind: "scene", sceneElementId: schnappschuss.element.element_id },
16703
+ hinweise: [
16704
+ "Kein Bildaufbau und keine Kamera \u2014 der Prompt wird ohne Kameravorgabe erzeugt.",
16705
+ "Kein Zielmodell \u2014 generische Promptableitung ohne Modelloptimierung.",
16706
+ schnappschuss.draft ? "Eingefroren wird der gespeicherte Entwurf. Nicht gespeicherte Aenderungen im Formular gehen nicht mit." : "Eingefroren wird die wirksame veroeffentlichte Version."
16707
+ ],
16708
+ blocker: szenenBlocker,
16709
+ onLauf: () => setNachladen((n) => n + 1)
16710
+ }
16711
+ ),
16712
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
16713
+ RunsPanel,
16714
+ {
16715
+ port,
16716
+ contextId,
16717
+ source: { kind: "scene", sceneElementId: schnappschuss.element.element_id }
16718
+ }
16719
+ )
16720
+ ] }),
15918
16721
  typ === "scene_setup" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
15919
16722
  CapabilityPanel,
15920
16723
  {
@@ -15939,6 +16742,26 @@ var ElementDetail = ({
15939
16742
  ] });
15940
16743
  };
15941
16744
 
16745
+ // src/features/szenen/areas/useSchmalesDisplay.ts
16746
+ var import_react10 = require("react");
16747
+ var SCHMALE_ANSICHT = "(max-width: 760px)";
16748
+ function messen(abfrage) {
16749
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
16750
+ return window.matchMedia(abfrage).matches;
16751
+ }
16752
+ function useSchmalesDisplay(abfrage = SCHMALE_ANSICHT) {
16753
+ const [schmal, setSchmal] = (0, import_react10.useState)(() => messen(abfrage));
16754
+ (0, import_react10.useEffect)(() => {
16755
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
16756
+ const liste = window.matchMedia(abfrage);
16757
+ const aktualisieren = () => setSchmal(liste.matches);
16758
+ aktualisieren();
16759
+ liste.addEventListener?.("change", aktualisieren);
16760
+ return () => liste.removeEventListener?.("change", aktualisieren);
16761
+ }, [abfrage]);
16762
+ return schmal;
16763
+ }
16764
+
15942
16765
  // src/features/szenen/areas/ElementsArea.tsx
15943
16766
  var import_jsx_runtime10 = require("react/jsx-runtime");
15944
16767
  var ElementsArea = ({
@@ -15947,18 +16770,31 @@ var ElementsArea = ({
15947
16770
  author = "szenen-view",
15948
16771
  restrictToTypes,
15949
16772
  allTypesLabel,
16773
+ listTitle,
15950
16774
  onSelect
15951
16775
  }) => {
15952
16776
  const auswahlTypen = restrictToTypes ?? SZENEN_ELEMENT_TYPES;
15953
- const [typ, setTyp] = (0, import_react10.useState)(
15954
- restrictToTypes && restrictToTypes.length === 1 ? restrictToTypes[0] : ""
15955
- );
15956
- const [zeigeStillgelegte, setZeigeStillgelegte] = (0, import_react10.useState)(false);
15957
- const [gewaehlt, setGewaehlt] = (0, import_react10.useState)(null);
15958
- const [neuerTitel, setNeuerTitel] = (0, import_react10.useState)("");
15959
- const [neuerTyp, setNeuerTyp] = (0, import_react10.useState)(auswahlTypen[0]);
15960
- const [notiz, setNotiz] = (0, import_react10.useState)(null);
15961
- const [anlegend, setAnlegend] = (0, import_react10.useState)(false);
16777
+ const einzelTyp = auswahlTypen.length === 1 ? auswahlTypen[0] : null;
16778
+ const gemischt = auswahlTypen.length > 1;
16779
+ const ueberschrift = listTitle ?? (einzelTyp ? elementTypPlural(einzelTyp) : "Bausteine");
16780
+ const einzahl = einzelTyp ? elementTypLabel(einzelTyp) : "Objekt";
16781
+ const [typ, setTyp] = (0, import_react11.useState)(einzelTyp ?? "");
16782
+ const [zeigeStillgelegte, setZeigeStillgelegte] = (0, import_react11.useState)(false);
16783
+ const [gewaehlt, setGewaehlt] = (0, import_react11.useState)(null);
16784
+ const [neuerTitel, setNeuerTitel] = (0, import_react11.useState)("");
16785
+ const [neuerTyp, setNeuerTyp] = (0, import_react11.useState)(auswahlTypen[0]);
16786
+ const [notiz, setNotiz] = (0, import_react11.useState)(null);
16787
+ const [anlegend, setAnlegend] = (0, import_react11.useState)(false);
16788
+ const [anlageOffen, setAnlageOffen] = (0, import_react11.useState)(false);
16789
+ const schmal = useSchmalesDisplay();
16790
+ const [ansicht, setAnsicht] = (0, import_react11.useState)("liste");
16791
+ const zeigeListe = !schmal || ansicht === "liste";
16792
+ const zeigeDetail = !schmal || ansicht === "detail";
16793
+ const waehle = (elementId) => {
16794
+ setGewaehlt(elementId);
16795
+ setAnsicht("detail");
16796
+ onSelect?.(elementId);
16797
+ };
15962
16798
  const [phase, neuLaden] = usePortQuery(
15963
16799
  () => port.elements.listElements({
15964
16800
  contextId,
@@ -15967,128 +16803,199 @@ var ElementsArea = ({
15967
16803
  }),
15968
16804
  [port, contextId, typ, zeigeStillgelegte]
15969
16805
  );
15970
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "szenen-elements", "data-testid": "bereich-elemente", children: [
15971
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "szenen-elements__filter", children: [
15972
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
15973
- "Typ",
15974
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
15975
- "select",
15976
- {
15977
- "data-testid": "filter-typ",
15978
- value: typ,
15979
- onChange: (e) => setTyp(e.target.value),
15980
- children: [
15981
- (!restrictToTypes || restrictToTypes.length > 1) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: allTypesLabel ?? "alle Typen" }),
15982
- auswahlTypen.map((t) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: t, children: t }, t))
15983
- ]
15984
- }
15985
- )
15986
- ] }),
15987
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
15988
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
15989
- "input",
15990
- {
15991
- type: "checkbox",
15992
- "data-testid": "filter-stillgelegt",
15993
- checked: zeigeStillgelegte,
15994
- onChange: (e) => setZeigeStillgelegte(e.target.checked)
15995
- }
15996
- ),
15997
- "stillgelegte Elemente einblenden"
15998
- ] }),
15999
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "data-testid": "neu-laden", onClick: neuLaden, children: "neu laden" })
16000
- ] }),
16001
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
16002
- "form",
16003
- {
16004
- className: "szenen-elements__create",
16005
- "data-testid": "element-anlegen",
16006
- onSubmit: async (e) => {
16007
- e.preventDefault();
16008
- if (!neuerTitel.trim()) return;
16009
- setAnlegend(true);
16010
- const ergebnis = await port.elements.createElement({
16011
- type: neuerTyp,
16012
- title: neuerTitel.trim(),
16013
- contextId
16014
- });
16015
- setNotiz(noticeFor(ergebnis, `Element \u201E${neuerTitel.trim()}" anlegen`));
16016
- setAnlegend(false);
16017
- if (ergebnis.kind === "ok") {
16018
- setNeuerTitel("");
16019
- setGewaehlt(ergebnis.value.element_id);
16020
- onSelect?.(ergebnis.value.element_id);
16021
- neuLaden();
16022
- }
16023
- },
16024
- children: [
16025
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16026
- "input",
16806
+ const anlageSchliessen = () => {
16807
+ setAnlageOffen(false);
16808
+ setNeuerTitel("");
16809
+ };
16810
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
16811
+ "div",
16812
+ {
16813
+ className: "szenen-elements",
16814
+ "data-testid": "bereich-elemente",
16815
+ "data-ansicht": schmal ? ansicht : "beide",
16816
+ children: [
16817
+ zeigeListe && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "szenen-elements__master", "data-testid": "elemente-master", children: [
16818
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "szenen-elements__toolbar", children: [
16819
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "szenen-elements__heading", children: ueberschrift }),
16820
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16821
+ "button",
16822
+ {
16823
+ type: "button",
16824
+ className: "szenen-elements__new",
16825
+ "data-testid": "neu-oeffnen",
16826
+ "aria-expanded": anlageOffen,
16827
+ onClick: () => {
16828
+ setNotiz(null);
16829
+ if (anlageOffen) anlageSchliessen();
16830
+ else setAnlageOffen(true);
16831
+ },
16832
+ children: "+ Neu"
16833
+ }
16834
+ )
16835
+ ] }),
16836
+ gemischt && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "szenen-elements__scope", children: [
16837
+ "Art",
16838
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
16839
+ "select",
16840
+ {
16841
+ "data-testid": "filter-typ",
16842
+ value: typ,
16843
+ onChange: (e) => setTyp(e.target.value),
16844
+ children: [
16845
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: allTypesLabel ?? "alle Typen" }),
16846
+ auswahlTypen.map((t) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: t, children: elementTypPlural(t) }, t))
16847
+ ]
16848
+ }
16849
+ )
16850
+ ] }),
16851
+ anlageOffen && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
16852
+ "form",
16027
16853
  {
16028
- "data-testid": "neuer-titel",
16029
- value: neuerTitel,
16030
- placeholder: "Titel des neuen Elements",
16031
- onChange: (e) => setNeuerTitel(e.target.value)
16854
+ className: "szenen-elements__create",
16855
+ "data-testid": "element-anlegen",
16856
+ onSubmit: async (e) => {
16857
+ e.preventDefault();
16858
+ if (!neuerTitel.trim()) return;
16859
+ setAnlegend(true);
16860
+ const gewuenschterTyp = einzelTyp ?? neuerTyp;
16861
+ const titel = neuerTitel.trim();
16862
+ const ergebnis = await port.elements.createElement({
16863
+ type: gewuenschterTyp,
16864
+ title: titel,
16865
+ contextId
16866
+ });
16867
+ setNotiz(noticeFor(
16868
+ ergebnis,
16869
+ `${elementTypLabel(gewuenschterTyp)} \u201E${titel}" anlegen`
16870
+ ));
16871
+ setAnlegend(false);
16872
+ if (ergebnis.kind === "ok") {
16873
+ anlageSchliessen();
16874
+ waehle(ergebnis.value.element_id);
16875
+ neuLaden();
16876
+ }
16877
+ },
16878
+ children: [
16879
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "szenen-elements__create-title", children: [
16880
+ einzelTyp ? `Neue ${einzahl}` : "Titel",
16881
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16882
+ "input",
16883
+ {
16884
+ "data-testid": "neuer-titel",
16885
+ value: neuerTitel,
16886
+ autoFocus: true,
16887
+ placeholder: einzelTyp ? `Titel der neuen ${einzahl}` : "Titel",
16888
+ onChange: (e) => setNeuerTitel(e.target.value)
16889
+ }
16890
+ )
16891
+ ] }),
16892
+ gemischt && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "szenen-elements__create-type", children: [
16893
+ "Art",
16894
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16895
+ "select",
16896
+ {
16897
+ "data-testid": "neuer-typ",
16898
+ value: neuerTyp,
16899
+ onChange: (e) => setNeuerTyp(e.target.value),
16900
+ children: auswahlTypen.map((t) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: t, children: elementTypLabel(t) }, t))
16901
+ }
16902
+ )
16903
+ ] }),
16904
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "szenen-elements__create-actions", children: [
16905
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16906
+ "button",
16907
+ {
16908
+ type: "submit",
16909
+ "data-testid": "anlegen",
16910
+ disabled: anlegend || !neuerTitel.trim(),
16911
+ children: "anlegen"
16912
+ }
16913
+ ),
16914
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16915
+ "button",
16916
+ {
16917
+ type: "button",
16918
+ "data-testid": "anlegen-abbrechen",
16919
+ onClick: anlageSchliessen,
16920
+ children: "abbrechen"
16921
+ }
16922
+ )
16923
+ ] })
16924
+ ]
16032
16925
  }
16033
16926
  ),
16034
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16035
- "select",
16927
+ notiz && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { "data-testid": "anlegen-notiz", "data-tone": notiz.tone, children: notiz.text }),
16928
+ phase.status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { "data-testid": "elemente-laden", children: "Elemente werden geladen \u2026" }),
16929
+ phase.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { "data-testid": "elemente-fehler", role: "alert", children: [
16930
+ "Elemente konnten nicht geladen werden: ",
16931
+ phase.message,
16932
+ phase.retryable && " \u2014 ein erneuter Versuch kann helfen."
16933
+ ] }),
16934
+ phase.status === "ready" && phase.value.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { "data-testid": "elemente-leer", children: [
16935
+ typ ? `Keine ${elementTypPlural(typ)} in diesem Kontext.` : "Nichts in diesem Kontext.",
16936
+ " ",
16937
+ 'Mit \u201E+ Neu" anlegen.'
16938
+ ] }),
16939
+ phase.status === "ready" && phase.value.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { className: "szenen-elements__list", "data-testid": "elemente-liste", children: phase.value.map((element) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("li", { "data-element-id": element.element_id, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
16940
+ "button",
16941
+ {
16942
+ type: "button",
16943
+ "data-testid": `element-waehlen-${element.element_id}`,
16944
+ "aria-current": element.element_id === gewaehlt,
16945
+ className: element.element_id === gewaehlt ? "is-selected" : void 0,
16946
+ onClick: () => waehle(element.element_id),
16947
+ children: [
16948
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { className: "szenen-elements__title", children: element.title || "Unbenanntes Element" }),
16949
+ gemischt && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "szenen-elements__type", children: elementTypLabel(element.type) }),
16950
+ element.subtype && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "szenen-elements__subtype", children: element.subtype }),
16951
+ element.retired && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "szenen-elements__retired", children: "stillgelegt" })
16952
+ ]
16953
+ }
16954
+ ) }, element.element_id)) }),
16955
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("details", { className: "szenen-elements__options", "data-testid": "listen-optionen", children: [
16956
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("summary", { children: "Listenoptionen" }),
16957
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "szenen-elements__filter", children: [
16958
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
16959
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16960
+ "input",
16961
+ {
16962
+ type: "checkbox",
16963
+ "data-testid": "filter-stillgelegt",
16964
+ checked: zeigeStillgelegte,
16965
+ onChange: (e) => setZeigeStillgelegte(e.target.checked)
16966
+ }
16967
+ ),
16968
+ "stillgelegte Elemente einblenden"
16969
+ ] }),
16970
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "data-testid": "neu-laden", onClick: neuLaden, children: "neu laden" })
16971
+ ] })
16972
+ ] })
16973
+ ] }),
16974
+ zeigeDetail && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "szenen-elements__detail", "data-testid": "elemente-detail-spalte", children: [
16975
+ schmal && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16976
+ "button",
16036
16977
  {
16037
- "data-testid": "neuer-typ",
16038
- value: neuerTyp,
16039
- onChange: (e) => setNeuerTyp(e.target.value),
16040
- children: auswahlTypen.map((t) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: t, children: t }, t))
16978
+ type: "button",
16979
+ className: "szenen-elements__back",
16980
+ "data-testid": "zurueck-zur-liste",
16981
+ onClick: () => setAnsicht("liste"),
16982
+ children: "\u2190 Zur\xFCck zur Liste"
16041
16983
  }
16042
16984
  ),
16043
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "submit", "data-testid": "anlegen", disabled: anlegend || !neuerTitel.trim(), children: "anlegen" })
16044
- ]
16045
- }
16046
- ),
16047
- notiz && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { "data-testid": "anlegen-notiz", "data-tone": notiz.tone, children: notiz.text }),
16048
- phase.status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { "data-testid": "elemente-laden", children: "Elemente werden geladen \u2026" }),
16049
- phase.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { "data-testid": "elemente-fehler", role: "alert", children: [
16050
- "Elemente konnten nicht geladen werden: ",
16051
- phase.message,
16052
- phase.retryable && " \u2014 ein erneuter Versuch kann helfen."
16053
- ] }),
16054
- phase.status === "ready" && phase.value.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { "data-testid": "elemente-leer", children: [
16055
- "Keine Elemente in diesem Kontext",
16056
- typ ? ` mit Typ \u201E${typ}"` : "",
16057
- "."
16058
- ] }),
16059
- phase.status === "ready" && phase.value.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { className: "szenen-elements__list", "data-testid": "elemente-liste", children: phase.value.map((element) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("li", { "data-element-id": element.element_id, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
16060
- "button",
16061
- {
16062
- type: "button",
16063
- "aria-current": element.element_id === gewaehlt,
16064
- className: element.element_id === gewaehlt ? "is-selected" : void 0,
16065
- onClick: () => {
16066
- setGewaehlt(element.element_id);
16067
- onSelect?.(element.element_id);
16068
- },
16069
- children: [
16070
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { className: "szenen-elements__title", children: element.title || "Unbenanntes Element" }),
16071
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "szenen-elements__type", children: element.type }),
16072
- element.subtype && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "szenen-elements__subtype", children: element.subtype }),
16073
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "szenen-elements__technical", children: [
16074
- "ID ",
16075
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("code", { className: "szenen-elements__id", children: element.element_id })
16076
- ] }),
16077
- element.retired && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "szenen-elements__retired", children: "stillgelegt" })
16078
- ]
16079
- }
16080
- ) }, element.element_id)) }),
16081
- gewaehlt && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16082
- ElementDetail,
16083
- {
16084
- port,
16085
- elementId: gewaehlt,
16086
- contextId,
16087
- author,
16088
- onChanged: neuLaden
16089
- }
16090
- )
16091
- ] });
16985
+ gewaehlt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
16986
+ ElementDetail,
16987
+ {
16988
+ port,
16989
+ elementId: gewaehlt,
16990
+ contextId,
16991
+ author,
16992
+ onChanged: neuLaden
16993
+ }
16994
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "szenen-elements__empty-detail", "data-testid": "keine-auswahl", children: "Nichts ausgew\xE4hlt. Ein Eintrag aus der Liste \xF6ffnet die Bearbeitung." })
16995
+ ] })
16996
+ ]
16997
+ }
16998
+ );
16092
16999
  };
16093
17000
 
16094
17001
  // src/features/szenen/areas/SceneArea.tsx
@@ -16101,14 +17008,15 @@ var SceneArea = ({ port, contextId }) => /* @__PURE__ */ (0, import_jsx_runtime1
16101
17008
  // src/features/szenen/areas/SetupArea.tsx
16102
17009
  var import_jsx_runtime12 = require("react/jsx-runtime");
16103
17010
  var SetupArea = ({ port, contextId }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "szenen-setup", "data-testid": "bereich-setup", children: [
16104
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "szenen-area__lead", children: "Scene Setups und Camera Rigs dieses Kontexts." }),
17011
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "szenen-area__lead", children: "Bildaufbauten, Kameras und Stile dieses Kontexts." }),
16105
17012
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
16106
17013
  ElementsArea,
16107
17014
  {
16108
17015
  port,
16109
17016
  contextId,
16110
17017
  restrictToTypes: ["scene_setup", "camera_preset", "camera_pattern", "style"],
16111
- allTypesLabel: "alle Bildaufbau-Typen"
17018
+ allTypesLabel: "alle Bildaufbau-Typen",
17019
+ listTitle: "Bildaufbau"
16112
17020
  }
16113
17021
  )
16114
17022
  ] });
@@ -16116,34 +17024,35 @@ var SetupArea = ({ port, contextId }) => /* @__PURE__ */ (0, import_jsx_runtime1
16116
17024
  // src/features/szenen/areas/ShotArea.tsx
16117
17025
  var import_jsx_runtime13 = require("react/jsx-runtime");
16118
17026
  var ShotArea = ({ port, contextId }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "szenen-shot", "data-testid": "bereich-shot", children: [
16119
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "szenen-area__lead", children: "Shots dieses Kontexts. Auswahl zeigt Runden und startet Prompt-L\xE4ufe." }),
17027
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "szenen-area__lead", children: "Prompts dieses Kontexts. Auswahl zeigt Runden und startet Prompt-L\xE4ufe." }),
16120
17028
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
16121
17029
  ElementsArea,
16122
17030
  {
16123
17031
  port,
16124
17032
  contextId,
16125
17033
  restrictToTypes: ["shot", "shot_concept", "target_model"],
16126
- allTypesLabel: "alle Prompt-Typen"
17034
+ allTypesLabel: "alle Prompt-Typen",
17035
+ listTitle: "Prompts"
16127
17036
  }
16128
17037
  )
16129
17038
  ] });
16130
17039
 
16131
17040
  // src/features/szenen/areas/MediaArea.tsx
16132
- var import_react11 = require("react");
17041
+ var import_react12 = require("react");
16133
17042
  var import_jsx_runtime14 = require("react/jsx-runtime");
16134
17043
  var leer = async () => ({ kind: "ok", value: [] });
16135
17044
  var MediaArea = ({ port }) => {
16136
17045
  const media = port.media;
16137
- const [versionInput, setVersionInput] = (0, import_react11.useState)("");
16138
- const [versionId, setVersionId] = (0, import_react11.useState)("");
16139
- const [itemInput, setItemInput] = (0, import_react11.useState)("");
16140
- const [itemId, setItemId] = (0, import_react11.useState)("");
16141
- const [assetId, setAssetId] = (0, import_react11.useState)("");
16142
- const [role, setRole] = (0, import_react11.useState)("reference");
16143
- const [position, setPosition] = (0, import_react11.useState)("0");
16144
- const [notiz, setNotiz] = (0, import_react11.useState)(null);
16145
- const [busy, setBusy] = (0, import_react11.useState)(false);
16146
- const [refresh, setRefresh] = (0, import_react11.useState)(0);
17046
+ const [versionInput, setVersionInput] = (0, import_react12.useState)("");
17047
+ const [versionId, setVersionId] = (0, import_react12.useState)("");
17048
+ const [itemInput, setItemInput] = (0, import_react12.useState)("");
17049
+ const [itemId, setItemId] = (0, import_react12.useState)("");
17050
+ const [assetId, setAssetId] = (0, import_react12.useState)("");
17051
+ const [role, setRole] = (0, import_react12.useState)("reference");
17052
+ const [position, setPosition] = (0, import_react12.useState)("0");
17053
+ const [notiz, setNotiz] = (0, import_react12.useState)(null);
17054
+ const [busy, setBusy] = (0, import_react12.useState)(false);
17055
+ const [refresh, setRefresh] = (0, import_react12.useState)(0);
16147
17056
  const [versionPhase] = usePortQuery(
16148
17057
  () => versionId ? media.listVersionMedia(versionId) : leer(),
16149
17058
  [media, versionId, refresh]
@@ -16269,10 +17178,10 @@ var MediaArea = ({ port }) => {
16269
17178
  };
16270
17179
 
16271
17180
  // src/features/szenen/areas/DeriveArea.tsx
16272
- var import_react14 = require("react");
17181
+ var import_react15 = require("react");
16273
17182
 
16274
17183
  // src/features/szenen/areas/RecoveryPanel.tsx
16275
- var import_react12 = require("react");
17184
+ var import_react13 = require("react");
16276
17185
  var import_jsx_runtime15 = require("react/jsx-runtime");
16277
17186
  var Diagnosen = ({ befunde, testId }) => {
16278
17187
  if (befunde.length === 0) return null;
@@ -16323,11 +17232,11 @@ var Ausbeute = ({ bewertung }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)
16323
17232
  ] })
16324
17233
  ] });
16325
17234
  var RecoveryPanel = ({ port, lauf }) => {
16326
- const [arbeitskopie, setArbeitskopie] = (0, import_react12.useState)(null);
16327
- const [bewertung, setBewertung] = (0, import_react12.useState)(null);
16328
- const [gesichert, setGesichert] = (0, import_react12.useState)(null);
16329
- const [meldung, setMeldung] = (0, import_react12.useState)(null);
16330
- const [laeuft, setLaeuft] = (0, import_react12.useState)(false);
17235
+ const [arbeitskopie, setArbeitskopie] = (0, import_react13.useState)(null);
17236
+ const [bewertung, setBewertung] = (0, import_react13.useState)(null);
17237
+ const [gesichert, setGesichert] = (0, import_react13.useState)(null);
17238
+ const [meldung, setMeldung] = (0, import_react13.useState)(null);
17239
+ const [laeuft, setLaeuft] = (0, import_react13.useState)(false);
16331
17240
  if (!port.derivation) return null;
16332
17241
  if (typeof lauf.raw_output !== "string" || lauf.raw_output.length === 0) return null;
16333
17242
  const derivation = port.derivation;
@@ -16450,12 +17359,12 @@ var RecoveryPanel = ({ port, lauf }) => {
16450
17359
  };
16451
17360
 
16452
17361
  // src/features/szenen/areas/ChainActions.tsx
16453
- var import_react13 = require("react");
17362
+ var import_react14 = require("react");
16454
17363
  var import_jsx_runtime16 = require("react/jsx-runtime");
16455
17364
  var ChainActions = ({ port, runId, recoveryId }) => {
16456
- const [graph, setGraph] = (0, import_react13.useState)(null);
16457
- const [meldung, setMeldung] = (0, import_react13.useState)(null);
16458
- const [laeuft, setLaeuft] = (0, import_react13.useState)(false);
17365
+ const [graph, setGraph] = (0, import_react14.useState)(null);
17366
+ const [meldung, setMeldung] = (0, import_react14.useState)(null);
17367
+ const [laeuft, setLaeuft] = (0, import_react14.useState)(false);
16459
17368
  if (!port.derivation) return null;
16460
17369
  const derivation = port.derivation;
16461
17370
  const runs = port.runs;
@@ -16521,7 +17430,13 @@ var ChainActions = ({ port, runId, recoveryId }) => {
16521
17430
  ] }),
16522
17431
  shotKnoten && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
16523
17432
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { children: 'Die Entw\xFCrfe lassen sich jetzt unter \u201E1 \xB7 Bausteine" \xE4ndern. Der Prompt-Lauf friert den Stand ein, den er dabei vorfindet \u2014 dieselbe Aktion steht auch am Shot selbst, unter \u201E4 \xB7 Prompt".' }),
16524
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChainPromptAction, { port, shotElementId: shotKnoten.elementId })
17433
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
17434
+ PromptStartAction,
17435
+ {
17436
+ port,
17437
+ source: { kind: "draft_chain", shotElementId: shotKnoten.elementId }
17438
+ }
17439
+ )
16525
17440
  ] }),
16526
17441
  meldung && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "szenen-error", role: "alert", "data-testid": "kette-meldung", children: meldung })
16527
17442
  ] });
@@ -16535,8 +17450,8 @@ var MODUS_TEXT = {
16535
17450
  image_prompt: "Bild und Prompt"
16536
17451
  };
16537
17452
  var BelegFeld = ({ titel, text, testId, offen }) => {
16538
- const [kopiert, setKopiert] = (0, import_react14.useState)(false);
16539
- const feld = (0, import_react14.useRef)(null);
17453
+ const [kopiert, setKopiert] = (0, import_react15.useState)(false);
17454
+ const feld = (0, import_react15.useRef)(null);
16540
17455
  async function kopieren() {
16541
17456
  try {
16542
17457
  await navigator.clipboard.writeText(text);
@@ -16632,7 +17547,7 @@ function readAsBase642(datei) {
16632
17547
  });
16633
17548
  }
16634
17549
  var BildWaehler = ({ port, gewaehlt, onWaehlen, onEntfernen }) => {
16635
- const [suche, setSuche] = (0, import_react14.useState)("");
17550
+ const [suche, setSuche] = (0, import_react15.useState)("");
16636
17551
  const [bilder] = usePortQuery(
16637
17552
  () => port.imageLibrary.listImages({ search: suche.trim() || void 0, limit: 60 }),
16638
17553
  [port, suche]
@@ -16690,19 +17605,19 @@ async function digestOf(datei) {
16690
17605
  return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, "0")).join("");
16691
17606
  }
16692
17607
  var DeriveArea = ({ port, contextId }) => {
16693
- const [policyVersionId, setPolicyVersionId] = (0, import_react14.useState)("");
16694
- const [modus, setModus] = (0, import_react14.useState)("prompt");
16695
- const [promptText, setPromptText] = (0, import_react14.useState)("");
16696
- const [dateien, setDateien] = (0, import_react14.useState)([]);
16697
- const [bestandsbilder, setBestandsbilder] = (0, import_react14.useState)([]);
16698
- const [laeuft, setLaeuft] = (0, import_react14.useState)(false);
16699
- const [lauf, setLauf] = (0, import_react14.useState)(null);
16700
- const [meldung, setMeldung] = (0, import_react14.useState)(null);
16701
- const [uebernommen, setUebernommen] = (0, import_react14.useState)({});
16702
- const [titel, setTitel] = (0, import_react14.useState)({});
16703
- const [referenzen, setReferenzen] = (0, import_react14.useState)({});
16704
- const [beanstandung, setBeanstandung] = (0, import_react14.useState)(null);
16705
- const [zusatz, setZusatz] = (0, import_react14.useState)("");
17608
+ const [policyVersionId, setPolicyVersionId] = (0, import_react15.useState)("");
17609
+ const [modus, setModus] = (0, import_react15.useState)("prompt");
17610
+ const [promptText, setPromptText] = (0, import_react15.useState)("");
17611
+ const [dateien, setDateien] = (0, import_react15.useState)([]);
17612
+ const [bestandsbilder, setBestandsbilder] = (0, import_react15.useState)([]);
17613
+ const [laeuft, setLaeuft] = (0, import_react15.useState)(false);
17614
+ const [lauf, setLauf] = (0, import_react15.useState)(null);
17615
+ const [meldung, setMeldung] = (0, import_react15.useState)(null);
17616
+ const [uebernommen, setUebernommen] = (0, import_react15.useState)({});
17617
+ const [titel, setTitel] = (0, import_react15.useState)({});
17618
+ const [referenzen, setReferenzen] = (0, import_react15.useState)({});
17619
+ const [beanstandung, setBeanstandung] = (0, import_react15.useState)(null);
17620
+ const [zusatz, setZusatz] = (0, import_react15.useState)("");
16706
17621
  const [regeln] = usePortQuery(
16707
17622
  () => port.derivation.listPolicies(contextId),
16708
17623
  [port, contextId]
@@ -17086,9 +18001,9 @@ var SzenenView = ({
17086
18001
  initialArea,
17087
18002
  onAreaChange
17088
18003
  }) => {
17089
- const bereiche = (0, import_react15.useMemo)(() => areasFor(port), [port]);
17090
- const faehig = (0, import_react15.useMemo)(() => capabilitiesOf(port), [port]);
17091
- const [aktiv, setAktiv] = (0, import_react15.useState)(() => resolveArea(port, initialArea));
18004
+ const bereiche = (0, import_react16.useMemo)(() => areasFor(port), [port]);
18005
+ const faehig = (0, import_react16.useMemo)(() => capabilitiesOf(port), [port]);
18006
+ const [aktiv, setAktiv] = (0, import_react16.useState)(() => resolveArea(port, initialArea));
17092
18007
  const wechsle = (id) => {
17093
18008
  setAktiv(id);
17094
18009
  onAreaChange?.(id);
@@ -17119,7 +18034,16 @@ var SzenenView = ({
17119
18034
  )) }),
17120
18035
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "szenen-view__area", "aria-label": aktuellerBereich.title, children: [
17121
18036
  aktiv === "derive" && port.derivation && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DeriveArea, { port, contextId }),
17122
- aktiv === "elements" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ElementsArea, { port, contextId }),
18037
+ aktiv === "elements" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
18038
+ ElementsArea,
18039
+ {
18040
+ port,
18041
+ contextId,
18042
+ restrictToTypes: BAUSTEIN_TYPES,
18043
+ allTypesLabel: "alle Bausteine",
18044
+ listTitle: "Bausteine"
18045
+ }
18046
+ ),
17123
18047
  aktiv === "scene" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SceneArea, { port, contextId }),
17124
18048
  aktiv === "setup" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SetupArea, { port, contextId }),
17125
18049
  aktiv === "shot" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ShotArea, { port, contextId }),
@@ -17144,6 +18068,7 @@ var SzenenView = ({
17144
18068
  ELEMENT_VERSION_SCHEMA_FILE,
17145
18069
  FLOW_EXECUTION_PATH,
17146
18070
  PROBE_VERSION_ID,
18071
+ PROMPT_RULE_EFFECT,
17147
18072
  REFERENCE_FIELD,
17148
18073
  RULES_WITHOUT_CAPABILITY_EFFECT,
17149
18074
  RULE_SCOPES,
@@ -17180,6 +18105,7 @@ var SzenenView = ({
17180
18105
  checkDraftChainMeta,
17181
18106
  checkElementType,
17182
18107
  checkImageExecutionProfile,
18108
+ checkImageExecutionProfiles,
17183
18109
  checkImageModelParameters,
17184
18110
  checkOptionalId,
17185
18111
  checkParents,
@@ -17228,7 +18154,10 @@ var SzenenView = ({
17228
18154
  derivationPoliciesOf,
17229
18155
  deriveItemFromRun,
17230
18156
  deriveLineage,
18157
+ describableContent,
17231
18158
  describeTargetModelFailure,
18159
+ diagnosticOfFinding,
18160
+ diagnosticOfSchemaError,
17232
18161
  differentialSteps,
17233
18162
  draftRevisionOf,
17234
18163
  elementStoreContractChecks,
@@ -17243,6 +18172,7 @@ var SzenenView = ({
17243
18172
  firstError,
17244
18173
  formatSchemaErrors,
17245
18174
  freezeDraftChain,
18175
+ freezeSceneWorkingState,
17246
18176
  getSzenenSchemas,
17247
18177
  hasPlacementCapability,
17248
18178
  isKnownElementType,
@@ -17259,22 +18189,26 @@ var SzenenView = ({
17259
18189
  parseRunResponse,
17260
18190
  preferredHeadRevisionOf,
17261
18191
  preferredVersionId,
18192
+ promptDiagnosticsOf,
17262
18193
  publishedHeadsOf,
17263
18194
  recoveriesForRun,
17264
18195
  recoveryStatusOf,
17265
18196
  reduceElementEvents,
17266
18197
  resolveArea,
17267
18198
  resolvePreferredHead,
18199
+ resolveScenePayload,
17268
18200
  resolveShot,
17269
18201
  resolveShotPayload,
17270
18202
  resolveTargetModelOver,
17271
18203
  resolverFromQueries,
17272
18204
  roundOfRun,
18205
+ rulesWithoutPromptEffect,
17273
18206
  runElementStoreContract,
17274
18207
  runPromptDerivation,
17275
18208
  runPublishChecks,
17276
18209
  runSceneDerivation,
17277
18210
  runStoreDifferential,
18211
+ sceneOnlyCapabilities,
17278
18212
  scopeOfPath,
17279
18213
  selectableTargetModels,
17280
18214
  showChain,