655 lines
17 KiB
TypeScript
655 lines
17 KiB
TypeScript
export const PRODUCTION_CONTRACT_VERSIONS = {
|
|
sourceAnalysis: 'source_analysis_v1',
|
|
adaptationBible: 'adaptation_bible_v1',
|
|
episodePlan: 'episode_plan_v1',
|
|
sceneScript: 'scene_script_v1',
|
|
assetPlan: 'asset_plan_v1',
|
|
sceneGeography: 'scene_geography_v1',
|
|
shotExecution: 'shot_execution_v1',
|
|
stageQuality: 'stage_quality_v1',
|
|
stageReviewDelta: 'stage_review_delta_v1',
|
|
shotQcDelta: 'shot_qc_delta_v1',
|
|
promptRule: 'prompt_rule_v1'
|
|
} as const;
|
|
|
|
export type ProductionContractVersion =
|
|
(typeof PRODUCTION_CONTRACT_VERSIONS)[keyof typeof PRODUCTION_CONTRACT_VERSIONS];
|
|
|
|
export interface SourceRefV1 {
|
|
source_type: 'novel_snapshot' | 'chapter' | 'story_bible' | 'memory' | 'approved_decision';
|
|
source_id: string;
|
|
locator?: string;
|
|
quote?: string;
|
|
}
|
|
|
|
export interface SourceFactRefV1 {
|
|
fact: string;
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface SourceCharacterFactV1 {
|
|
character_id?: string;
|
|
name: string;
|
|
role: string;
|
|
goal: string;
|
|
fear?: string;
|
|
secrets: string[];
|
|
state: string;
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface SourceEventV1 {
|
|
id: string;
|
|
order: number;
|
|
event: string;
|
|
participants: string[];
|
|
consequence: string;
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface SourceAnalysisSpecV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.sourceAnalysis;
|
|
source_snapshot_id: string;
|
|
premise: string;
|
|
genre_promises: string[];
|
|
timeline: SourceEventV1[];
|
|
characters: SourceCharacterFactV1[];
|
|
relationships: SourceFactRefV1[];
|
|
world_rules: SourceFactRefV1[];
|
|
conflicts: SourceFactRefV1[];
|
|
mysteries: SourceFactRefV1[];
|
|
emotional_assets: SourceFactRefV1[];
|
|
visual_assets: SourceFactRefV1[];
|
|
immutable_facts: SourceFactRefV1[];
|
|
uncertain_facts: SourceFactRefV1[];
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface AdaptationDecisionV1 {
|
|
id: string;
|
|
operation: 'keep' | 'compress' | 'merge' | 'reorder' | 'remove' | 'add';
|
|
source_refs: SourceRefV1[];
|
|
target: string;
|
|
reason: string;
|
|
impact: string[];
|
|
continuity_risk: string;
|
|
approval_status: 'draft' | 'approved' | 'rejected';
|
|
}
|
|
|
|
export interface HookPolicyV1 {
|
|
mode: 'aggressive_0_3s' | 'suspense_0_5s' | 'cinematic_0_8s';
|
|
max_setup_ms: number;
|
|
require_visible_question: boolean;
|
|
require_episode_payoff: boolean;
|
|
max_repeated_hook_type: number;
|
|
}
|
|
|
|
export interface DialoguePolicyV1 {
|
|
language: string;
|
|
target_chars_per_second: number;
|
|
preserve_confirmed_lines: boolean;
|
|
require_listener_reaction: boolean;
|
|
}
|
|
|
|
export interface AdaptationBibleSpecV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.adaptationBible;
|
|
source_analysis_version_id: string;
|
|
format: {
|
|
orientation: '16:9';
|
|
target_episode_seconds: number;
|
|
episode_count_range: [number, number];
|
|
audience: string;
|
|
};
|
|
genre_contract: string;
|
|
tone_contract: string;
|
|
protagonist_contract: string;
|
|
central_dramatic_question: string;
|
|
main_arc: string;
|
|
character_arcs: Array<{ character_id: string; arc: string }>;
|
|
season_beats: Array<{ id: string; beat: string; consequence: string }>;
|
|
adaptation_decisions: AdaptationDecisionV1[];
|
|
hook_policy: HookPolicyV1;
|
|
dialogue_policy: DialoguePolicyV1;
|
|
visual_policy: string[];
|
|
sound_policy: string[];
|
|
prohibited_changes: string[];
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export type HookTypeV1 =
|
|
| 'crisis'
|
|
| 'result_first'
|
|
| 'identity_contrast'
|
|
| 'relationship_break'
|
|
| 'impossible_event'
|
|
| 'secret_exposure'
|
|
| 'countdown'
|
|
| 'forced_choice'
|
|
| 'high_value_promise'
|
|
| 'previous_hook_payoff';
|
|
|
|
export interface HookTimelineBeatV1 {
|
|
start_ms: number;
|
|
end_ms: number;
|
|
visual: string;
|
|
audio: string;
|
|
information_gain: string;
|
|
}
|
|
|
|
export interface OpeningHookSpecV1 {
|
|
type: HookTypeV1;
|
|
secondary_type?: HookTypeV1;
|
|
viewer_question: string;
|
|
character_at_risk: string[];
|
|
stakes: string;
|
|
visual_event: string;
|
|
audio_event: string;
|
|
timeline: HookTimelineBeatV1[];
|
|
relation_to_episode_conflict: string;
|
|
payoff_beat_id: string;
|
|
source_refs: SourceRefV1[];
|
|
anti_clickbait_check: string;
|
|
}
|
|
|
|
export interface EndingHookSpecV1 {
|
|
hook: string;
|
|
new_information: string;
|
|
next_episode_question: string;
|
|
state_change: string;
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface StoryStateRefV1 {
|
|
character_states: Record<string, string>;
|
|
active_conflicts: string[];
|
|
known_information: string[];
|
|
location_state?: string;
|
|
}
|
|
|
|
export interface EpisodeBeatV1 {
|
|
id: string;
|
|
type: 'setup' | 'escalation' | 'reversal' | 'choice' | 'climax' | 'aftermath' | 'hook';
|
|
beat: string;
|
|
character_action: string;
|
|
consequence: string;
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface EpisodePlanSpecV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.episodePlan;
|
|
adaptation_bible_version_id: string;
|
|
episode_number: number;
|
|
target_duration_ms: number;
|
|
hook_policy: HookPolicyV1;
|
|
opening_hook: OpeningHookSpecV1;
|
|
protagonist_goal: string;
|
|
obstacle: string;
|
|
stakes: string;
|
|
dramatic_question: string;
|
|
beats: EpisodeBeatV1[];
|
|
midpoint_change: string;
|
|
climax_choice: string;
|
|
irreversible_change: string;
|
|
ending_hook: EndingHookSpecV1;
|
|
entry_state: StoryStateRefV1;
|
|
exit_state: StoryStateRefV1;
|
|
source_refs: SourceRefV1[];
|
|
adaptation_decision_refs: string[];
|
|
}
|
|
|
|
export interface DialogueBeatV1 {
|
|
id: string;
|
|
character_id: string;
|
|
line: string;
|
|
intention: string;
|
|
subtext: string;
|
|
reaction_target?: string;
|
|
estimated_duration_ms: number;
|
|
}
|
|
|
|
export interface ActionBeatV1 {
|
|
id: string;
|
|
character_id?: string;
|
|
action: string;
|
|
trigger: string;
|
|
result: string;
|
|
estimated_duration_ms: number;
|
|
}
|
|
|
|
export interface SceneSpecV1 {
|
|
id: string;
|
|
location_asset_ref: string;
|
|
time_of_day: string;
|
|
entry_state: StoryStateRefV1;
|
|
scene_goal: string;
|
|
active_characters: string[];
|
|
character_objectives: Array<{ character_id: string; objective: string }>;
|
|
obstacle: string;
|
|
tactics: Array<{ character_id: string; tactic: string }>;
|
|
action_beats: ActionBeatV1[];
|
|
dialogue_beats: DialogueBeatV1[];
|
|
subtext: string;
|
|
turn: string;
|
|
exit_state: StoryStateRefV1;
|
|
estimated_duration_ms: number;
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface SceneScriptSpecV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.sceneScript;
|
|
episode_plan_version_id: string;
|
|
episode_number: number;
|
|
target_duration_ms: number;
|
|
scenes: SceneSpecV1[];
|
|
opening_hook_scene_id: string;
|
|
climax_scene_id: string;
|
|
ending_hook_scene_id: string;
|
|
dialogue_duration_estimate_ms: number;
|
|
total_duration_estimate_ms: number;
|
|
character_voice_checks: Array<{ character_id: string; check?: string; passed: boolean; issue?: string }>;
|
|
continuity_checks: Array<{ check?: string; passed: boolean; issue?: string }>;
|
|
}
|
|
|
|
export type AssetRequirementKindV1 =
|
|
| 'character_identity'
|
|
| 'character_state'
|
|
| 'crowd'
|
|
| 'location'
|
|
| 'prop'
|
|
| 'vfx';
|
|
|
|
export type AssetEntityTypeV1 =
|
|
| 'project_character'
|
|
| 'character_state'
|
|
| 'project_visual_asset'
|
|
| 'global_character'
|
|
| 'asset';
|
|
|
|
export interface AssetEntityRefV1 {
|
|
entity_type: AssetEntityTypeV1;
|
|
id: string;
|
|
}
|
|
|
|
export interface AssetCandidateRefV1 extends AssetEntityRefV1 {
|
|
reason: string;
|
|
approval_status: 'manual_review_required' | 'approved' | 'rejected';
|
|
}
|
|
|
|
export interface AssetRequirementV1 {
|
|
id: string;
|
|
kind: AssetRequirementKindV1;
|
|
name: string;
|
|
source_character_id?: string;
|
|
source_location_ref?: string;
|
|
reuse_decision: 'reuse' | 'create' | 'upgrade' | 'manual_review';
|
|
existing_ref: AssetEntityRefV1 | null;
|
|
candidate_refs: AssetCandidateRefV1[];
|
|
applies_to_scene_ids: string[];
|
|
priority: 'blocking' | 'high' | 'normal';
|
|
visual_brief: string;
|
|
continuity_locks: string[];
|
|
deliverables: string[];
|
|
acceptance_criteria: string[];
|
|
dependencies: string[];
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface AssetSceneBindingV1 {
|
|
scene_id: string;
|
|
location_requirement_ref: string;
|
|
character_requirement_refs: string[];
|
|
crowd_requirement_refs: string[];
|
|
prop_requirement_refs: string[];
|
|
vfx_requirement_refs: string[];
|
|
}
|
|
|
|
export interface AssetPlanSpecV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.assetPlan;
|
|
scene_script_version_id: string;
|
|
episode_number: number;
|
|
format: {
|
|
orientation: '16:9';
|
|
keyframe_resolution: '2560x1440';
|
|
video_resolution: '1920x1080';
|
|
};
|
|
inventory_snapshot: {
|
|
project_character_ids: string[];
|
|
project_visual_asset_ids: string[];
|
|
matching_global_character_ids: string[];
|
|
legacy_candidate_asset_ids: string[];
|
|
};
|
|
requirements: AssetRequirementV1[];
|
|
scene_bindings: AssetSceneBindingV1[];
|
|
creation_order: string[];
|
|
blocking_requirement_refs: string[];
|
|
quality_checks: Array<{ check: string; passed: boolean; issue?: string }>;
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface SpatialVectorV1 {
|
|
x: number;
|
|
y: number;
|
|
z: number;
|
|
}
|
|
|
|
export interface SceneGeographyZoneV1 {
|
|
id: string;
|
|
name: string;
|
|
purpose: string;
|
|
center: SpatialVectorV1;
|
|
bounds: string;
|
|
adjacent_zone_ids: string[];
|
|
}
|
|
|
|
export interface SceneGeographyPlacementV1 {
|
|
subject_ref: string;
|
|
subject_type: 'character' | 'faction' | 'crowd' | 'prop' | 'vfx_origin' | 'vfx_target';
|
|
faction_ref?: string;
|
|
zone_id: string;
|
|
world_position: SpatialVectorV1;
|
|
facing_vector: SpatialVectorV1;
|
|
screen_side: 'left' | 'center' | 'right' | 'background' | 'foreground';
|
|
eyeline_target_ref?: string;
|
|
vertical_relation: 'ground' | 'below' | 'above' | 'overhead';
|
|
}
|
|
|
|
export interface SceneGeographyAxisV1 {
|
|
id: string;
|
|
endpoint_a_ref: string;
|
|
endpoint_b_ref: string;
|
|
description: string;
|
|
screen_left_ref: string;
|
|
screen_right_ref: string;
|
|
safe_camera_side: string;
|
|
forbidden_camera_side: string;
|
|
crossing_policy: 'forbidden' | 'neutral_bridge_required' | 'motivated_crossing_allowed';
|
|
}
|
|
|
|
export interface SceneGeographyCameraPositionV1 {
|
|
id: string;
|
|
name: string;
|
|
world_position: SpatialVectorV1;
|
|
viewing_direction: SpatialVectorV1;
|
|
axis_side: 'safe' | 'on_axis' | 'forbidden';
|
|
allowed: boolean;
|
|
purpose: string;
|
|
preserves_screen_relationship: string;
|
|
}
|
|
|
|
export interface SceneGeographyActionVectorV1 {
|
|
id: string;
|
|
source_ref: string;
|
|
target_ref: string;
|
|
origin_zone_id: string;
|
|
target_zone_id: string;
|
|
world_direction: SpatialVectorV1;
|
|
screen_direction: string;
|
|
trajectory: string;
|
|
must_keep_origin_and_target_visible: boolean;
|
|
}
|
|
|
|
export interface SceneGeographyBlockingBeatV1 {
|
|
id: string;
|
|
trigger: string;
|
|
actor_ref: string;
|
|
start_zone_id: string;
|
|
end_zone_id: string;
|
|
facing_target_ref: string;
|
|
eyeline_target_ref: string;
|
|
action_vector_ref?: string;
|
|
continuity_result: string;
|
|
}
|
|
|
|
export interface SceneGeographySceneV1 {
|
|
scene_id: string;
|
|
location_requirement_ref: string;
|
|
world_layout: string;
|
|
coordinate_system: {
|
|
origin: string;
|
|
x_axis: string;
|
|
y_axis: string;
|
|
z_axis: string;
|
|
};
|
|
zones: SceneGeographyZoneV1[];
|
|
placements: SceneGeographyPlacementV1[];
|
|
primary_axis: SceneGeographyAxisV1;
|
|
camera_positions: SceneGeographyCameraPositionV1[];
|
|
action_vectors: SceneGeographyActionVectorV1[];
|
|
blocking_beats: SceneGeographyBlockingBeatV1[];
|
|
continuity_locks: string[];
|
|
forbidden_outcomes: string[];
|
|
required_spatial_anchor_refs: string[];
|
|
acceptance_criteria: string[];
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface SceneGeographySpecV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.sceneGeography;
|
|
asset_plan_version_id: string;
|
|
scene_script_version_id: string;
|
|
episode_number: number;
|
|
format: {
|
|
orientation: '16:9';
|
|
world_unit: 'meter';
|
|
coordinate_handedness: 'right_handed';
|
|
};
|
|
scene_geographies: SceneGeographySceneV1[];
|
|
global_continuity_locks: string[];
|
|
global_forbidden_outcomes: string[];
|
|
quality_checks: Array<{ check: string; passed: boolean; issue?: string }>;
|
|
source_refs: SourceRefV1[];
|
|
}
|
|
|
|
export interface FrameStateV1 {
|
|
composition: string;
|
|
character_positions: string;
|
|
eyelines: string;
|
|
action_state: string;
|
|
emotional_state: string;
|
|
camera_axis: string;
|
|
screen_direction: string;
|
|
lighting_state: string;
|
|
}
|
|
|
|
export interface ContinuityAnchorV1 {
|
|
type: 'character' | 'action' | 'eyeline' | 'camera_axis' | 'screen_direction' | 'sound' | 'prop' | 'light';
|
|
value: string;
|
|
}
|
|
|
|
export interface PerformanceBeatV1 {
|
|
character_id: string;
|
|
start_ms: number;
|
|
end_ms: number;
|
|
start_state: string;
|
|
trigger: string;
|
|
visible_action: string;
|
|
end_state: string;
|
|
}
|
|
|
|
export interface DialogueTimingV1 {
|
|
character_id: string;
|
|
start_ms: number;
|
|
end_ms: number;
|
|
spoken_text: string;
|
|
delivery: string;
|
|
listener_reaction?: string;
|
|
}
|
|
|
|
export interface ShotExecutionSpecV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.shotExecution;
|
|
scene_script_version_id: string;
|
|
scene_geography_version_id: string;
|
|
scene_id: string;
|
|
shot_number: number;
|
|
dramatic_purpose: string;
|
|
generation_unit: 'single_shot' | 'continuous_shot' | 'montage_unit';
|
|
target_duration_ms: number;
|
|
assets: {
|
|
character_state_refs: string[];
|
|
location_asset_ref: string;
|
|
prop_asset_refs: string[];
|
|
wardrobe_refs: string[];
|
|
vfx_asset_refs: string[];
|
|
};
|
|
blocking: {
|
|
focus: string;
|
|
pressure_source: string;
|
|
reaction_receiver: string;
|
|
positions: string;
|
|
movement_path: string;
|
|
};
|
|
geography_binding: {
|
|
axis_id: string;
|
|
camera_position_id: string;
|
|
placement_subject_refs: string[];
|
|
action_vector_refs: string[];
|
|
zone_ids: string[];
|
|
};
|
|
performance_timeline: PerformanceBeatV1[];
|
|
dialogue_timeline: DialogueTimingV1[];
|
|
camera: {
|
|
shot_size: string;
|
|
angle: string;
|
|
lens_intent: string;
|
|
movement: string;
|
|
movement_motivation: string;
|
|
camera_axis: string;
|
|
screen_direction: string;
|
|
landing_point: string;
|
|
};
|
|
lighting: {
|
|
key_light: string;
|
|
contrast: string;
|
|
dynamic_change: string;
|
|
};
|
|
vfx: Array<{
|
|
effect: string;
|
|
trigger: string;
|
|
interaction: string;
|
|
intensity_arc: string;
|
|
}>;
|
|
sound: {
|
|
ambience: string[];
|
|
dialogue_source: 'native_audio' | 'post_tts' | 'none';
|
|
sfx_hits: Array<{ at_ms: number; cue: string }>;
|
|
music_cue?: string;
|
|
sound_bridge?: string;
|
|
};
|
|
start_state: FrameStateV1;
|
|
end_state: FrameStateV1;
|
|
continuity_from_previous: ContinuityAnchorV1[];
|
|
continuity_to_next: ContinuityAnchorV1[];
|
|
edit_relation_to_previous:
|
|
| 'new_scene_cut'
|
|
| 'motivated_hard_cut'
|
|
| 'reaction_cut'
|
|
| 'match_cut'
|
|
| 'sound_bridge'
|
|
| 'continuous_motion';
|
|
cut_motivation: string;
|
|
generation_strategy: {
|
|
mode: 'text_only' | 'first_frame' | 'first_last_frame' | 'multi_reference';
|
|
reference_assets: Array<{
|
|
asset_id: string;
|
|
responsibility:
|
|
| 'character_identity'
|
|
| 'wardrobe_state'
|
|
| 'location_layout'
|
|
| 'prop_identity'
|
|
| 'start_frame'
|
|
| 'end_frame'
|
|
| 'action_pose'
|
|
| 'style_reference';
|
|
priority: number;
|
|
}>;
|
|
};
|
|
provider_requirements: {
|
|
native_audio_required: boolean;
|
|
dialogue_required: boolean;
|
|
max_reference_images?: number;
|
|
allowed_duration_ms?: number[];
|
|
};
|
|
acceptance_criteria: Array<{ field_path: string; expected: string; severity: 'minor' | 'major' | 'fatal' }>;
|
|
forbidden_outcomes: string[];
|
|
}
|
|
|
|
export interface QualityIssueV1 {
|
|
code: string;
|
|
field_path: string;
|
|
message: string;
|
|
severity: 'minor' | 'major' | 'fatal';
|
|
}
|
|
|
|
export interface StageQualityResultV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.stageQuality;
|
|
hard_gate_status: 'pass' | 'blocked';
|
|
hard_gate_issues: QualityIssueV1[];
|
|
dimension_scores: Record<string, number>;
|
|
weighted_score: number;
|
|
confidence: number;
|
|
fatal_issues: QualityIssueV1[];
|
|
repair_instructions: Array<{ field_path: string; instruction: string }>;
|
|
rubric_version: string;
|
|
}
|
|
|
|
export interface StageReviewDeltaV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.stageReviewDelta;
|
|
contract_type: 'source_analysis' | 'adaptation_bible' | 'episode_plan' | 'scene_script' | 'asset_plan' | 'scene_geography';
|
|
expected_contract_id: string;
|
|
reviewer_version: string;
|
|
verdict: 'pass' | 'repair_required';
|
|
issues: QualityIssueV1[];
|
|
repairs: Array<{
|
|
field_path: string;
|
|
instruction: string;
|
|
evidence_refs: SourceRefV1[];
|
|
}>;
|
|
reviewer_notes: string[];
|
|
}
|
|
|
|
export interface ShotQcDeltaV1 {
|
|
schema_version: typeof PRODUCTION_CONTRACT_VERSIONS.shotQcDelta;
|
|
expected_spec_version: string;
|
|
observed_asset_id: string;
|
|
matched: string[];
|
|
mismatches: Array<{
|
|
field_path: string;
|
|
expected: string;
|
|
observed: string;
|
|
severity: 'minor' | 'major' | 'fatal';
|
|
}>;
|
|
repair_scope: 'prompt' | 'reference' | 'duration' | 'route' | 'script';
|
|
repair_instructions: string[];
|
|
}
|
|
|
|
export type PromptRuleStageV1 =
|
|
| 'source'
|
|
| 'adaptation'
|
|
| 'episode'
|
|
| 'script'
|
|
| 'assets'
|
|
| 'geography'
|
|
| 'shot'
|
|
| 'qc'
|
|
| 'timeline';
|
|
|
|
export interface PromptRuleCandidateV1 {
|
|
id: string;
|
|
source_prompt_refs: string[];
|
|
stage: PromptRuleStageV1;
|
|
scope: 'global' | 'genre' | 'provider' | 'project';
|
|
genre_tags: string[];
|
|
provider_codes: string[];
|
|
original_text: string;
|
|
normalized_rule: string;
|
|
activation_condition: string;
|
|
expected_improvement: string;
|
|
evidence_refs: string[];
|
|
positive_examples: string[];
|
|
negative_examples: string[];
|
|
conflicts_with: string[];
|
|
status: 'candidate' | 'testing' | 'approved' | 'deprecated';
|
|
reviewer_id?: string;
|
|
rule_version: typeof PRODUCTION_CONTRACT_VERSIONS.promptRule;
|
|
}
|