nx_director_pipeline.nx source
↩ module page · 171 lines · 6398 B
1// nx_director_pipeline.nx -- end-to-end demonstration: the substrate IS
2// the director.
3//
4// One pure NishiLang program walks the canonical pipeline:
5//
6// 1. allocate a multi-stage arc (a "day-as-a-movie" event)
7// 2. for each stage, resolve into a DirectorsNote (the per-moment
8// decision the director hands to the crew)
9// 3. simulate a "render outcome" by writing per-element survival
10// verdicts into a SurvivalReport
11// 4. aggregate -> PreflightTier (GOOD / DRIFT / BROKEN)
12// 5. count session totals + emit a final director-summary verdict
13//
14// No Python, no service layer, no subprocess. Per the arc-and-moment-
15// are-king cardinal: arcs + moments live in NishiLang, not in glue code.
16//
17// Per the graduated-intervention cardinal:
18// any MISSING -> BROKEN (regen with corrective phrasing)
19// any PARTIAL (no missing) -> DRIFT (ship + log trend, NO regen)
20// any UNMEASURED (rest ok) -> DRIFT
21// all SURVIVED -> GOOD (ship + archive as exemplar)
22//
23// genealogy_id: kurosawa_director_centric + jenkins_pipelines
24// lineage_id: substrate_native_director
25
26// nx_safety_envelope:
27// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
28// sil_target: SIL1
29// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
30// verdict: NOT_YET_EVALUATED
31
32import "nx_syscalls.nx"
33import "nx_runtime.nx"
34import "nx_tier.nx"
35import "nx_prng.nx"
36import "nx_arc.nx"
37import "nx_directors_note.nx"
38import "nx_moment_resolve.nx"
39import "nx_intent_survival.nx"
40
41// ===== Pipeline summary record =====================================
42//
43// Compact session-wide rollup so callers can read one struct instead
44// of walking per-stage state.
45
46struct PipelineSummary {
47 n_stages: nx_int, // total stages run
48 n_good: nx_int, // count of GOOD outcomes
49 n_drift: nx_int, // count of DRIFT outcomes
50 n_broken: nx_int, // count of BROKEN outcomes
51 last_seq: nx_int // last moment_seq emitted (for chaining)
52}
53
54const NX_PIPE_SUMMARY_BYTES: nx_int = 40 // 5 fields * 8
55
56func nx_pipe_summary_alloc() -> *PipelineSummary {
57 let s: *PipelineSummary = (sys_mmap(NX_PIPE_SUMMARY_BYTES)) as *PipelineSummary
58 s.n_stages = 0
59 s.n_good = 0
60 s.n_drift = 0
61 s.n_broken = 0
62 s.last_seq = 0 - 1
63 return s
64}
65
66// ===== Simulated render outcome ====================================
67//
68// The substrate doesn't ship its own generative renderer in this
69// smoke; instead it simulates how a real renderer's output would feed
70// back into the SurvivalReport. Three named scenarios:
71//
72// PERFECT -- everything the director asked for survived rendering
73// DRIFTED -- outfit + affect partially rendered, rest survived
74// BROKEN -- pose missing entirely (e.g., wrong body geometry)
75//
76// Real production would replace these with CLIP probes / color checks /
77// per-element verdicts. The PIPELINE shape stays identical.
78
79const NX_DPS_PERFECT: nx_int = 0
80const NX_DPS_DRIFTED: nx_int = 1
81const NX_DPS_BROKEN: nx_int = 2
82
83func _simulate_perfect(rpt: *SurvivalReport) -> nx_int {
84 var i: nx_int = 0
85 while i < NX_IS_N_ELEMS {
86 nx_is_set_verdict(rpt, i, NX_IS_SURVIVED)
87 i = i + 1
88 }
89 return 0
90}
91
92func _simulate_drifted(rpt: *SurvivalReport) -> nx_int {
93 // Most elements survive; outfit + affect drift (color shift,
94 // softer emotional read). No outright missing.
95 var i: nx_int = 0
96 while i < NX_IS_N_ELEMS {
97 nx_is_set_verdict(rpt, i, NX_IS_SURVIVED)
98 i = i + 1
99 }
100 nx_is_set_verdict(rpt, NX_IS_ELEM_OUTFIT, NX_IS_PARTIAL)
101 nx_is_set_verdict(rpt, NX_IS_ELEM_AFFECT, NX_IS_PARTIAL)
102 return 0
103}
104
105func _simulate_broken(rpt: *SurvivalReport) -> nx_int {
106 // Pose missing -- e.g., the renderer produced bad body geometry
107 // and the requested action isn't visible. Triggers regen.
108 var i: nx_int = 0
109 while i < NX_IS_N_ELEMS {
110 nx_is_set_verdict(rpt, i, NX_IS_SURVIVED)
111 i = i + 1
112 }
113 nx_is_set_verdict(rpt, NX_IS_ELEM_POSE, NX_IS_MISSING)
114 return 0
115}
116
117func _simulate(rpt: *SurvivalReport, scenario: nx_int) -> nx_int {
118 if scenario == NX_DPS_PERFECT { return _simulate_perfect(rpt) }
119 if scenario == NX_DPS_DRIFTED { return _simulate_drifted(rpt) }
120 if scenario == NX_DPS_BROKEN { return _simulate_broken(rpt) }
121 return 0 - 1
122}
123
124// ===== Per-stage step ==============================================
125//
126// Resolve the stage into a DirectorsNote, simulate the render outcome,
127// aggregate survival, fold the verdict back into both the DirectorsNote
128// and the session summary.
129//
130// Returns the aggregated PreflightTier (GOOD / DRIFT / BROKEN).
131
132func nx_director_pipeline_step(arc: *Arc, stage_idx: nx_int,
133 scenario: nx_int,
134 prng_state: *i64,
135 summary: *PipelineSummary) -> nx_int {
136 // Build the DirectorsNote (the director's instruction for this moment)
137 let dn: *DirectorsNote = nx_dn_alloc()
138 dn.character_id = 7
139 dn.body_archetype_id = 9
140 nx_moment_resolve(arc, stage_idx, summary.last_seq, prng_state, dn)
141 summary.last_seq = dn.moment_seq
142
143 // Simulate the renderer + run intent_survival
144 let rpt: *SurvivalReport = nx_is_alloc(arc.arc_id, dn.moment_seq)
145 _simulate(rpt, scenario)
146 let tier: nx_int = nx_is_aggregate(rpt)
147
148 // Fold the verdict into the DirectorsNote so downstream services
149 // see the final director-stamped tier on the same envelope.
150 nx_is_apply_to_dn(rpt, dn)
151
152 // Session bookkeeping
153 summary.n_stages = summary.n_stages + 1
154 if tier == NX_PFT_GOOD { summary.n_good = summary.n_good + 1 }
155 if tier == NX_PFT_DRIFT { summary.n_drift = summary.n_drift + 1 }
156 if tier == NX_PFT_BROKEN { summary.n_broken = summary.n_broken + 1 }
157 return tier
158}
159
160// ===== Pipeline-level verdict ======================================
161//
162// Convert session totals into a single substrate-wide PreflightTier:
163// any BROKEN -> BROKEN
164// any DRIFT (no BROKEN) -> DRIFT
165// all GOOD -> GOOD
166
167func nx_director_pipeline_verdict(summary: *PipelineSummary) -> nx_int {
168 if summary.n_broken > 0 { return NX_PFT_BROKEN }
169 if summary.n_drift > 0 { return NX_PFT_DRIFT }
170 return NX_PFT_GOOD
171}