code wiki / (root) / nx_directors_note.nx

nx_directors_note.nx source

↩ module page · 452 lines · 19718 B

1// nx_directors_note.nx -- the canonical "director's note" envelope. 2// 3// Per cardinal feedback-arc-and-moment-are-king-cinematographer-pattern: 4// arc + moment ARE the director. Everything downstream (scene composer, 5// prompt builder, wardrobe, gen-img, quality gate) is CREW executing 6// the director's vision. Falling back to a downstream service's 7// defaults = ignoring the director = the 3000-batch sprawl. 8// 9// This primitive is the typed envelope that flows through the entire 10// render pipeline. Every service consumes a *DirectorsNote (never a 11// flat dict), reads what it needs, raises NX_DN_UNDERSPECIFIED if a 12// required field is unset. No service is allowed to silently default. 13// 14// Per cardinal feedback-new-capabilities-go-to-nishilang-not-python: 15// this lives in NishiLang, not in Python. Elder AI's Python services 16// will subprocess-consume the compiled binary (or HTTP-call a NishiLang 17// micro-service wrapping it) as the migration progresses. 18// 19// Per cardinal feedback-audit-before-build-togaf-into-complete-system: 20// audited existing nx_ primitives 2026-05-15 — no current primitive 21// owns this concept. `nx_mise_en_scene` is render-side scoring (not 22// the authority). `nx_sketch_moments` is statistical moments (not 23// narrative). `nx_beauty_score` ships the AwardClass enum we compose 24// against here, not duplicate. 25// 26// Per cardinal feedback-linux-clear-tools-not-sprawl: this is ONE tool 27// with ONE job — carry the director's intent end-to-end. No business 28// logic; just the typed envelope + validators + builders. 29// 30// === Composition ================================================== 31// 32// nx_beauty_score.nx AwardClass constants (S/A/B/OFF_CANON) 33// nx_canon_proportions proportion canon (substrate of anatomy) 34// nx_string_ops buf+len string handling for names/keys 35// nx_result typed OK/ERR envelope 36// nx_tier nx_int / nx_size aliases 37// 38// genealogy_id: aristotle_unities + chomsky_grammar + brecht_alienation_effect + 39// eisenstein_montage + propp_morphology + houdini_director_sop 40// lineage_id: nx_directors_note_v1 41 42// nx_safety_envelope: 43// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 44// sil_target: SIL1 45// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 46// verdict: NOT_YET_EVALUATED 47 48import "nx_syscalls.nx" 49import "nx_tier.nx" 50 51// ===== Sealed-enum: DirectorRole ================================== 52// 53// Who is directing this moment. The substrate is content-domain- 54// agnostic; what makes a moment coherent is that ONE director is in 55// charge of it. 56 57const NX_DR_EXTERNAL_USER: nx_int = 0 // human user typed an explicit request 58const NX_DR_EXTERNAL_SYSTEM: nx_int = 1 // batch driver, scheduler, scene planner 59const NX_DR_COMPANION: nx_int = 2 // companion (Elara) authored from her own decisions 60const NX_DR_ARC_AUTHORED: nx_int = 3 // hand-curated arc-stage author 61const NX_DR_DYNAMIC_LLM: nx_int = 4 // LLM-generated arc 62const NX_DR_N_ROLES: nx_int = 5 63 64func nx_dr_role_is_valid(r: nx_int) -> nx_int { 65 if r < 0 { return 0 } 66 if r >= NX_DR_N_ROLES { return 0 } 67 return 1 68} 69 70// ===== Sealed-enum: ContentDomain ================================== 71// 72// The content space the moment lives in. Substrate is domain-agnostic; 73// downstream services adapt their vocabulary via this tag. This is 74// what lets the same envelope ferry MUNDANE study sessions, FANTASY 75// quests, EROTIC scenes, RPG combats through the SAME pipeline. 76 77const NX_CD_MUNDANE: nx_int = 0 // study, cooking, reading, dressing 78const NX_CD_INTIMATE: nx_int = 1 // romance, affection, sensual 79const NX_CD_EROTIC: nx_int = 2 // explicit sexual content 80const NX_CD_FANTASY: nx_int = 3 // magic, mythical, otherworldly 81const NX_CD_RPG: nx_int = 4 // combat, exploration, dialogue 82const NX_CD_NARRATIVE: nx_int = 5 // story beats, character moments 83const NX_CD_N_DOMAINS: nx_int = 6 84 85func nx_cd_domain_is_valid(d: nx_int) -> nx_int { 86 if d < 0 { return 0 } 87 if d >= NX_CD_N_DOMAINS { return 0 } 88 return 1 89} 90 91// ===== Sealed-enum: AffectAxis ==================================== 92// 93// The character's emotional posture for this moment. TYPED axis the 94// director sets, not an unscored float. Substrate can route subtle 95// drift on this axis to DRIFT tier, not BROKEN, per the graduated- 96// intervention cardinal. 97 98const NX_AF_NEUTRAL: nx_int = 0 99const NX_AF_VULNERABLE: nx_int = 1 100const NX_AF_PLAYFUL: nx_int = 2 101const NX_AF_DOMINANT: nx_int = 3 102const NX_AF_INTIMATE: nx_int = 4 103const NX_AF_ANXIOUS: nx_int = 5 104const NX_AF_JOYFUL: nx_int = 6 105const NX_AF_MELANCHOLIC: nx_int = 7 106const NX_AF_FOCUSED: nx_int = 8 // studying, working, reading 107const NX_AF_REVERENT: nx_int = 9 // awe, worship, profound moment 108const NX_AF_PLAYFUL_BRATTY: nx_int = 10 109const NX_AF_N_AXES: nx_int = 11 110 111func nx_af_axis_is_valid(a: nx_int) -> nx_int { 112 if a < 0 { return 0 } 113 if a >= NX_AF_N_AXES { return 0 } 114 return 1 115} 116 117// ===== Sealed-enum: SourceTag ===================================== 118// 119// Where this moment's content came from. Lets the substrate trace 120// back to source and propose pool-expansion when something fails. 121 122const NX_ST_STAGE_POOL: nx_int = 0 // picked from arc stage's pool 123const NX_ST_CONSTELLATION: nx_int = 1 // pre-validated cluster 124const NX_ST_EROTIC_SCENARIO: nx_int = 2 // choreography source 125const NX_ST_CHAT_OVERRIDE: nx_int = 3 // user typed an override 126const NX_ST_COMPANION_DECISION: nx_int = 4 // Elara picked this 127const NX_ST_DYNAMIC_EXPANSION: nx_int = 5 // LLM-expanded for novelty 128const NX_ST_POV_SCENARIO: nx_int = 6 // POV framing source 129const NX_ST_N_TAGS: nx_int = 7 130 131func nx_st_tag_is_valid(t: nx_int) -> nx_int { 132 if t < 0 { return 0 } 133 if t >= NX_ST_N_TAGS { return 0 } 134 return 1 135} 136 137// ===== Sealed-enum: AwardClass (compose with nx_beauty_score) ====== 138// 139// nx_beauty_score.nx already defines NX_BEAUTY_S_CLASS / A_CLASS / 140// B_CLASS / OFF_CANON / UNKNOWN constants. Rather than duplicate, 141// we re-export them under the DN_AWARD_ prefix so callers reading 142// this file see the full envelope vocabulary in one place. The 143// underlying values are identical and the predicate composes. 144 145const NX_DN_AWARD_UNVERIFIED: nx_int = 0 // = NX_BEAUTY_UNKNOWN 146const NX_DN_AWARD_S_CLASS: nx_int = 1 // = NX_BEAUTY_S_CLASS 147const NX_DN_AWARD_A_CLASS: nx_int = 2 // = NX_BEAUTY_A_CLASS 148const NX_DN_AWARD_B_CLASS: nx_int = 3 // = NX_BEAUTY_B_CLASS 149const NX_DN_AWARD_OFF_CANON: nx_int = 4 // = NX_BEAUTY_OFF_CANON 150const NX_DN_AWARD_N_CLASSES: nx_int = 5 151 152func nx_dn_award_is_valid(a: nx_int) -> nx_int { 153 if a < 0 { return 0 } 154 if a >= NX_DN_AWARD_N_CLASSES { return 0 } 155 return 1 156} 157 158// ===== Sealed-enum: PreflightTier ================================= 159// 160// Per cardinal feedback-graduated-intervention-no-chainsaw: three 161// sealed verdicts not binary pass/fail. 162 163const NX_PFT_GOOD: nx_int = 0 // ship, archive as exemplar 164const NX_PFT_DRIFT: nx_int = 1 // ship + log trend, NO regen 165const NX_PFT_BROKEN: nx_int = 2 // block + regen with corrective phrasing 166const NX_PFT_N_TIERS: nx_int = 3 167 168func nx_pft_tier_is_valid(t: nx_int) -> nx_int { 169 if t < 0 { return 0 } 170 if t >= NX_PFT_N_TIERS { return 0 } 171 return 1 172} 173 174// ===== Sealed-enum: Underspecified error codes ==================== 175// 176// When a downstream service finds a needed field unset, it returns 177// the specific code so moment_generator can expand its vocabulary. 178 179const NX_DN_UNDERSPEC_NONE: nx_int = 0 180const NX_DN_UNDERSPEC_OUTFIT: nx_int = 1 181const NX_DN_UNDERSPEC_LOCATION: nx_int = 2 182const NX_DN_UNDERSPEC_POSE: nx_int = 3 183const NX_DN_UNDERSPEC_AFFECT: nx_int = 4 184const NX_DN_UNDERSPEC_LIGHTING: nx_int = 5 185const NX_DN_UNDERSPEC_CAMERA: nx_int = 6 186const NX_DN_UNDERSPEC_ACTIVITY: nx_int = 7 187const NX_DN_UNDERSPEC_CHARACTER: nx_int = 8 188const NX_DN_UNDERSPEC_BODY_ARCHETYPE: nx_int = 9 189const NX_DN_UNDERSPEC_DOMAIN: nx_int = 10 190const NX_DN_UNDERSPEC_N_CODES: nx_int = 11 191 192func nx_dn_underspec_is_valid(c: nx_int) -> nx_int { 193 if c < 0 { return 0 } 194 if c >= NX_DN_UNDERSPEC_N_CODES { return 0 } 195 return 1 196} 197 198// ===== Sealed-enum: Perspective + ShotSize (cinematography) ======= 199// 200// Promoted from Python's svc-arc-moments/models.py into the canonical 201// NishiLang home. Same semantics; integer-backed so they compose 202// with the sealed-enum substrate convention. 203 204const NX_PERSP_POV: nx_int = 0 // she's engaging with you 205const NX_PERSP_POV_BOYFRIEND: nx_int = 1 // boyfriend POV, intimate framing 206const NX_PERSP_VOYEUR: nx_int = 2 // you're watching unnoticed 207const NX_PERSP_CANDID: nx_int = 3 // candid/natural, aware but not posing 208const NX_PERSP_SELFIE: nx_int = 4 // she's taking a selfie 209const NX_PERSP_THIRD: nx_int = 5 // cinematic third-person 210const NX_PERSP_N_PERSPS: nx_int = 6 211 212func nx_persp_is_valid(p: nx_int) -> nx_int { 213 if p < 0 { return 0 } 214 if p >= NX_PERSP_N_PERSPS { return 0 } 215 return 1 216} 217 218const NX_SHOT_ECU: nx_int = 0 // extreme close-up (eyes, lips) 219const NX_SHOT_BCU: nx_int = 1 // big close-up (face fills frame) 220const NX_SHOT_CU: nx_int = 2 // close-up (head and shoulders) 221const NX_SHOT_MCU: nx_int = 3 // medium close-up (chest up) 222const NX_SHOT_MS: nx_int = 4 // medium shot (waist up) 223const NX_SHOT_MWS: nx_int = 5 // medium wide shot (knees up) 224const NX_SHOT_WS: nx_int = 6 // wide shot (full body) 225const NX_SHOT_FS: nx_int = 7 // full shot (full body with environment) 226const NX_SHOT_N_SHOTS: nx_int = 8 227 228func nx_shot_is_valid(s: nx_int) -> nx_int { 229 if s < 0 { return 0 } 230 if s >= NX_SHOT_N_SHOTS { return 0 } 231 return 1 232} 233 234// ===== BodyMark struct ============================================ 235// 236// A persistent physical mark on the actor (hickey, sweat, tears, 237// wetness). Carries across moments within an arc so continuity 238// holds visually. Per additive-only-data cardinal: marks accumulate; 239// is_current=0 preserves history without delete. 240 241struct BodyMark { 242 mark_kind: nx_int, // sealed enum BMK_HICKEY/SWEAT/TEARS/WETNESS/... 243 location_id: nx_int, // sealed enum (neck_left, thigh_inner, lips, ...) 244 intensity_q10: nx_int, // 0..1024 245 applied_at_seq: nx_int, // moment sequence index that created the mark 246 is_current: nx_int // 1 = active, 0 = historical 247} 248 249const NX_BMK_HICKEY: nx_int = 0 250const NX_BMK_SWEAT: nx_int = 1 251const NX_BMK_TEARS: nx_int = 2 252const NX_BMK_WETNESS: nx_int = 3 253const NX_BMK_FLUSH: nx_int = 4 254const NX_BMK_SALIVA: nx_int = 5 255const NX_BMK_N_KINDS: nx_int = 6 256 257func nx_bmk_kind_is_valid(k: nx_int) -> nx_int { 258 if k < 0 { return 0 } 259 if k >= NX_BMK_N_KINDS { return 0 } 260 return 1 261} 262 263// ===== DirectorsNote struct ======================================== 264// 265// The CANONICAL envelope. Carried unchanged through every step of 266// the render pipeline. Built by moment_generator (or a companion 267// authoring her own decision), consumed by every downstream service. 268// 269// All ID fields are i64 IDs (interned keys, not strings) — keeps the 270// struct fixed-size + compatible with NishiLang's no-string-storage 271// substrate. The Python facade resolves IDs to strings on emit; the 272// substrate-side primitive operates on IDs. 273 274struct DirectorsNote { 275 // === Identity ================================================= 276 arc_id: nx_int, 277 arc_stage: nx_int, 278 moment_seq: nx_int, // monotone per-arc sequence number 279 character_id: nx_int, 280 281 // === Provenance + authority =================================== 282 director_role: nx_int, // DR_EXTERNAL_USER / COMPANION / ... 283 source_tag: nx_int, // ST_STAGE_POOL / CONSTELLATION / ... 284 content_domain: nx_int, // CD_MUNDANE / EROTIC / FANTASY / ... 285 286 // === Actor's state =========================================== 287 outfit_key_id: nx_int, // -> outfits table; substrate resolves 288 affect_axis: nx_int, // AF_FOCUSED / PLAYFUL / VULNERABLE / ... 289 arousal_q10: nx_int, // 0..1024 (so any caller can scale) 290 body_archetype_id: nx_int, // tall_feminine_height / ... (the user's "we like" cluster) 291 exposure_level_q10: nx_int, // 0..1024 (bridges categorical wardrobe_state) 292 293 // === Scene ===================================================== 294 location_id: nx_int, // -> locations table 295 activity_id: nx_int, // -> activities table 296 pose_id: nx_int, // -> poses table (renamed from body_position) 297 time_of_day: nx_int, // sealed enum 298 lighting_mood: nx_int, // sealed enum (warm/dramatic/soft/...) 299 fg_light_id: nx_int, // -> three-plane lighting (was on CoherentScene) 300 mg_light_id: nx_int, 301 bg_light_id: nx_int, 302 303 // === Camera =================================================== 304 perspective: nx_int, // PERSP_POV / VOYEUR / SELFIE / ... 305 shot_size: nx_int, // SHOT_ECU / CU / MS / WS / FS / ... 306 camera_motivation_id: nx_int, // why the camera is here 307 composition_id: nx_int, // rule_of_thirds / centered / diagonal / ... 308 gaze_direction: nx_int, // sealed: at_camera / away / down / ... 309 310 // === Continuity ============================================== 311 prev_moment_seq: nx_int, // for cross-moment continuity refs 312 constellation_id: nx_int, // pre-validated cluster 313 pov_scenario_id: nx_int, // POV framing source 314 315 // === Quality + verification (per s-class-canon cardinal) ==== 316 award_class: nx_int, // DN_AWARD_UNVERIFIED until evaluated 317 preflight_tier: nx_int, // PFT_GOOD / DRIFT / BROKEN; UNVERIFIED until gated 318 refine_iteration: nx_int, // which iteration of the auto-fix loop 319 320 // === Underspec tracking ===================================== 321 underspec_code: nx_int // DN_UNDERSPEC_NONE in healthy state 322} 323 324const NX_DN_FIELDS: nx_int = 31 // total fields in DirectorsNote 325const NX_DN_BYTES: nx_int = 248 // = 31 * 8; NishiLang consts must be literals 326 327// ===== Builder ==================================================== 328// 329// Allocates a DirectorsNote with neutral defaults (UNDERSPEC_NONE, 330// UNVERIFIED award, refine_iteration=0). Caller MUST set the 331// required fields before passing to a downstream service. 332 333func nx_dn_alloc() -> *DirectorsNote { 334 let dn: *DirectorsNote = (sys_mmap(NX_DN_BYTES)) as *DirectorsNote 335 dn.arc_id = 0 336 dn.arc_stage = 0 337 dn.moment_seq = 0 338 dn.character_id = 0 339 dn.director_role = NX_DR_EXTERNAL_SYSTEM 340 dn.source_tag = NX_ST_STAGE_POOL 341 dn.content_domain = NX_CD_MUNDANE 342 dn.outfit_key_id = 0 343 dn.affect_axis = NX_AF_NEUTRAL 344 dn.arousal_q10 = 0 345 dn.body_archetype_id = 0 346 dn.exposure_level_q10 = 0 347 dn.location_id = 0 348 dn.activity_id = 0 349 dn.pose_id = 0 350 dn.time_of_day = 0 351 dn.lighting_mood = 0 352 dn.fg_light_id = 0 353 dn.mg_light_id = 0 354 dn.bg_light_id = 0 355 dn.perspective = NX_PERSP_VOYEUR 356 dn.shot_size = NX_SHOT_MS 357 dn.camera_motivation_id = 0 358 dn.composition_id = 0 359 dn.gaze_direction = 0 360 dn.prev_moment_seq = 0 - 1 361 dn.constellation_id = 0 362 dn.pov_scenario_id = 0 363 dn.award_class = NX_DN_AWARD_UNVERIFIED 364 dn.preflight_tier = NX_PFT_GOOD 365 dn.refine_iteration = 0 366 dn.underspec_code = NX_DN_UNDERSPEC_NONE 367 return dn 368} 369 370// ===== Validators ================================================= 371// 372// Caller checks the envelope before handing off to a downstream 373// service. Returns NX_DN_UNDERSPEC_NONE if the envelope is complete 374// enough to render, else the specific code naming what's missing. 375 376func nx_dn_validate_for_render(dn: *DirectorsNote) -> nx_int { 377 if dn.outfit_key_id == 0 { return NX_DN_UNDERSPEC_OUTFIT } 378 if dn.location_id == 0 { return NX_DN_UNDERSPEC_LOCATION } 379 if dn.pose_id == 0 { return NX_DN_UNDERSPEC_POSE } 380 if dn.activity_id == 0 { return NX_DN_UNDERSPEC_ACTIVITY } 381 if dn.character_id == 0 { return NX_DN_UNDERSPEC_CHARACTER } 382 if dn.body_archetype_id == 0 { return NX_DN_UNDERSPEC_BODY_ARCHETYPE } 383 if nx_dr_role_is_valid(dn.director_role) == 0 { return NX_DN_UNDERSPEC_DOMAIN } 384 if nx_cd_domain_is_valid(dn.content_domain) == 0 { return NX_DN_UNDERSPEC_DOMAIN } 385 if nx_af_axis_is_valid(dn.affect_axis) == 0 { return NX_DN_UNDERSPEC_AFFECT } 386 if nx_persp_is_valid(dn.perspective) == 0 { return NX_DN_UNDERSPEC_CAMERA } 387 if nx_shot_is_valid(dn.shot_size) == 0 { return NX_DN_UNDERSPEC_CAMERA } 388 return NX_DN_UNDERSPEC_NONE 389} 390 391// ===== Accessors with safe defaults =============================== 392// 393// Downstream services use these instead of direct field reads when 394// they tolerate a sentinel. Strict callers use validate_for_render 395// first and refuse to proceed if underspecified. 396 397func nx_dn_award_class(dn: *DirectorsNote) -> nx_int { return dn.award_class } 398func nx_dn_preflight_tier(dn: *DirectorsNote) -> nx_int { return dn.preflight_tier } 399func nx_dn_director_role(dn: *DirectorsNote) -> nx_int { return dn.director_role } 400func nx_dn_content_domain(dn: *DirectorsNote) -> nx_int { return dn.content_domain } 401func nx_dn_affect_axis(dn: *DirectorsNote) -> nx_int { return dn.affect_axis } 402func nx_dn_underspec_code(dn: *DirectorsNote) -> nx_int { return dn.underspec_code } 403 404// ===== Tier router (graduated intervention) ======================= 405// 406// Translates an AwardClass into a PreflightTier per the graduated- 407// intervention cardinal. S/A = GOOD, B = DRIFT, OFF_CANON = BROKEN, 408// UNVERIFIED stays UNVERIFIED-routed-to-DRIFT (ship cautiously). 409 410func nx_dn_tier_from_award(award: nx_int) -> nx_int { 411 if award == NX_DN_AWARD_S_CLASS { return NX_PFT_GOOD } 412 if award == NX_DN_AWARD_A_CLASS { return NX_PFT_GOOD } 413 if award == NX_DN_AWARD_B_CLASS { return NX_PFT_DRIFT } 414 if award == NX_DN_AWARD_OFF_CANON { return NX_PFT_BROKEN } 415 return NX_PFT_DRIFT // UNVERIFIED -> DRIFT (cautious ship) 416} 417 418// ===== Companion-directed builder (Elara as director) ============= 419// 420// Convenience: when the companion authors a moment from her own 421// ontological decision (per the user's "external director or 422// one of the companions, elara in this case making ontological or 423// whatever type decisions"), this builder sets the role + source 424// in one call. 425 426func nx_dn_companion_authored(dn: *DirectorsNote, 427 character_id: nx_int, 428 domain: nx_int, 429 affect: nx_int) -> nx_int { 430 dn.director_role = NX_DR_COMPANION 431 dn.source_tag = NX_ST_COMPANION_DECISION 432 dn.character_id = character_id 433 dn.content_domain = domain 434 dn.affect_axis = affect 435 return 0 436} 437 438// ===== External-system builder (batch driver / scheduler) ========= 439 440func nx_dn_external_system_authored(dn: *DirectorsNote, 441 arc_id: nx_int, 442 arc_stage: nx_int, 443 moment_seq: nx_int, 444 domain: nx_int) -> nx_int { 445 dn.director_role = NX_DR_EXTERNAL_SYSTEM 446 dn.source_tag = NX_ST_STAGE_POOL 447 dn.arc_id = arc_id 448 dn.arc_stage = arc_stage 449 dn.moment_seq = moment_seq 450 dn.content_domain = domain 451 return 0 452}