nx_intent_survival.nx source
↩ module page · 243 lines · 9479 B
1// nx_intent_survival.nx -- did the director's intent survive the render?
2//
3// Closes the loop between the DirectorsNote (what was requested) and
4// the rendered image (what came out). Per cardinal feedback-graduated-
5// intervention-no-chainsaw: emits a TIERED verdict (GOOD/DRIFT/BROKEN),
6// never binary pass/fail.
7//
8// === Division of responsibility =====================================
9//
10// This substrate primitive does TWO things:
11//
12// (a) Defines the typed schema for per-element survival verdicts.
13// Each of the 7 director-named elements (outfit, location, pose,
14// affect, perspective, shot_size, camera_motivation) gets a
15// sealed-enum survival verdict.
16//
17// (b) Aggregates per-element verdicts into a single PreflightTier
18// per the graduated-intervention cardinal:
19// all SURVIVED -> GOOD
20// any MISSING -> BROKEN
21// any PARTIAL (no missing)-> DRIFT
22//
23// What this primitive does NOT do: compute the per-element verdict.
24// That's downstream work (CLIP probe, color histogram, learned classifier,
25// human label, etc.) — its output is fed in as a *i64 array of verdicts.
26//
27// The substrate-typed envelope is the canonical interchange; whoever
28// produces the per-element check (Python now, NishiLang vision primitive
29// when nx_vision_check ships, human reviewer in a labelled batch) all
30// feed the same schema.
31//
32// === Composition ====================================================
33//
34// nx_directors_note.nx -- DirectorsNote (the requested intent;
35// PreflightTier sealed enum)
36// nx_tier.nx -- nx_int alias
37//
38// genealogy_id: clip_2021 + checklist_alignment_eval +
39// in_toto_2019_provenance + faithful_explanation_inseq_2022
40// lineage_id: nx_intent_survival_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"
50import "nx_directors_note.nx"
51
52// ===== Sealed-enum: per-element survival ============================
53//
54// What happened to a specific requested element (outfit / location /
55// pose / affect / etc.) in the rendered image.
56
57const NX_IS_SURVIVED: nx_int = 0 // clearly present, recognisable
58const NX_IS_PARTIAL: nx_int = 1 // present but drifted (different color, soft proportion shift)
59const NX_IS_MISSING: nx_int = 2 // not present at all in the render
60const NX_IS_UNMEASURED: nx_int = 3 // no probe ran (caller didn't fill this slot)
61const NX_IS_N_VERDICTS: nx_int = 4
62
63func nx_is_verdict_is_valid(v: nx_int) -> nx_int {
64 if v < 0 { return 0 }
65 if v >= NX_IS_N_VERDICTS { return 0 }
66 return 1
67}
68
69// ===== Sealed-enum: element kind (slot in the verdicts buffer) =====
70//
71// The fixed-size flat-array layout of per-element verdicts. Indexing
72// is positional; caller writes verdicts[NX_IS_ELEM_OUTFIT] = SURVIVED,
73// etc.
74
75const NX_IS_ELEM_OUTFIT: nx_int = 0
76const NX_IS_ELEM_LOCATION: nx_int = 1
77const NX_IS_ELEM_POSE: nx_int = 2
78const NX_IS_ELEM_AFFECT: nx_int = 3
79const NX_IS_ELEM_PERSPECTIVE: nx_int = 4
80const NX_IS_ELEM_SHOT_SIZE: nx_int = 5
81const NX_IS_ELEM_CAMERA_MOTIVATION: nx_int = 6
82const NX_IS_ELEM_BODY_ARCHETYPE: nx_int = 7
83const NX_IS_N_ELEMS: nx_int = 8
84
85func nx_is_elem_is_valid(e: nx_int) -> nx_int {
86 if e < 0 { return 0 }
87 if e >= NX_IS_N_ELEMS { return 0 }
88 return 1
89}
90
91// ===== SurvivalReport struct ========================================
92//
93// The typed envelope per intent-survival pass.
94
95struct SurvivalReport {
96 moment_seq: nx_int, // which moment this report covers
97 arc_id: nx_int,
98 n_elems: nx_int, // = NX_IS_N_ELEMS for full coverage
99 verdicts: *i64, // [n_elems] of NX_IS_* sealed values
100 n_survived: nx_int, // count of NX_IS_SURVIVED
101 n_partial: nx_int, // count of NX_IS_PARTIAL
102 n_missing: nx_int, // count of NX_IS_MISSING
103 n_unmeasured: nx_int, // count of NX_IS_UNMEASURED
104 coverage_q10: nx_int, // = (n_survived * 1024) / n_elems
105 preflight_tier: nx_int // aggregated tier per graduated-intervention
106}
107
108const NX_IS_REPORT_BYTES: nx_int = 80 // 10 fields * 8 bytes/nx_int
109
110// ===== Builder ======================================================
111//
112// Allocate a SurvivalReport with a fresh verdicts buffer initialised
113// to UNMEASURED across all element slots. Caller fills via _set.
114
115func nx_is_alloc(arc_id: nx_int, moment_seq: nx_int) -> *SurvivalReport {
116 let r: *SurvivalReport = (sys_mmap(NX_IS_REPORT_BYTES)) as *SurvivalReport
117 r.arc_id = arc_id
118 r.moment_seq = moment_seq
119 r.n_elems = NX_IS_N_ELEMS
120 r.verdicts = (sys_mmap(NX_IS_N_ELEMS * NX_SIZEOF_NX_INT)) as *i64
121 var i: nx_int = 0
122 while i < NX_IS_N_ELEMS {
123 r.verdicts[i] = NX_IS_UNMEASURED
124 i = i + 1
125 }
126 r.n_survived = 0
127 r.n_partial = 0
128 r.n_missing = 0
129 r.n_unmeasured = NX_IS_N_ELEMS
130 r.coverage_q10 = 0
131 r.preflight_tier = NX_PFT_DRIFT // UNMEASURED defaults to DRIFT
132 return r
133}
134
135// ===== Per-element setter ===========================================
136//
137// Caller (CLIP probe / color check / human reviewer) writes the
138// verdict for one element. Returns -1 if elem or verdict invalid.
139
140func nx_is_set_verdict(r: *SurvivalReport, elem: nx_int, verdict: nx_int) -> nx_int {
141 if nx_is_elem_is_valid(elem) == 0 { return 0 - 1 }
142 if nx_is_verdict_is_valid(verdict) == 0 { return 0 - 1 }
143 r.verdicts[elem] = verdict
144 return 0
145}
146
147// ===== Per-element getter ===========================================
148
149func nx_is_get_verdict(r: *SurvivalReport, elem: nx_int) -> nx_int {
150 if nx_is_elem_is_valid(elem) == 0 { return NX_IS_UNMEASURED }
151 return r.verdicts[elem]
152}
153
154// ===== Aggregator: counts + coverage + tier =========================
155//
156// Walks the verdicts buffer, computes counts + coverage + PreflightTier
157// per graduated-intervention. Must be called after all per-element
158// verdicts have been set; idempotent — safe to re-call after updates.
159//
160// Tier logic (per the cardinal):
161// any MISSING -> BROKEN (regen with corrective phrasing)
162// any PARTIAL (no missing) -> DRIFT (ship + log trend, NO regen)
163// any UNMEASURED (rest ok) -> DRIFT (cautious ship until probe lands)
164// all SURVIVED -> GOOD (ship + exemplar archive)
165
166func nx_is_aggregate(r: *SurvivalReport) -> nx_int {
167 var ns: nx_int = 0
168 var np: nx_int = 0
169 var nm: nx_int = 0
170 var nu: nx_int = 0
171 var i: nx_int = 0
172 while i < r.n_elems {
173 let v: nx_int = r.verdicts[i]
174 if v == NX_IS_SURVIVED { ns = ns + 1 }
175 if v == NX_IS_PARTIAL { np = np + 1 }
176 if v == NX_IS_MISSING { nm = nm + 1 }
177 if v == NX_IS_UNMEASURED { nu = nu + 1 }
178 i = i + 1
179 }
180 r.n_survived = ns
181 r.n_partial = np
182 r.n_missing = nm
183 r.n_unmeasured = nu
184
185 // coverage_q10 = (n_survived * 1024) / n_elems
186 if r.n_elems > 0 {
187 r.coverage_q10 = (ns * 1024) / r.n_elems
188 } else {
189 r.coverage_q10 = 0
190 }
191
192 // Tier routing
193 var tier: nx_int = NX_PFT_GOOD
194 if nm > 0 {
195 tier = NX_PFT_BROKEN
196 } else {
197 if np > 0 { tier = NX_PFT_DRIFT }
198 if nu > 0 { tier = NX_PFT_DRIFT } // unmeasured = cautious ship
199 }
200 r.preflight_tier = tier
201 return tier
202}
203
204// ===== Underspec mapping ===========================================
205//
206// When the SurvivalReport indicates a BROKEN tier, name the FIRST
207// missing element so the auto-fix pipeline knows what to correct.
208// Returns one of nx_directors_note's NX_DN_UNDERSPEC_* codes.
209
210func nx_is_first_missing_underspec(r: *SurvivalReport) -> nx_int {
211 var i: nx_int = 0
212 while i < r.n_elems {
213 if r.verdicts[i] == NX_IS_MISSING {
214 if i == NX_IS_ELEM_OUTFIT { return NX_DN_UNDERSPEC_OUTFIT }
215 if i == NX_IS_ELEM_LOCATION { return NX_DN_UNDERSPEC_LOCATION }
216 if i == NX_IS_ELEM_POSE { return NX_DN_UNDERSPEC_POSE }
217 if i == NX_IS_ELEM_AFFECT { return NX_DN_UNDERSPEC_AFFECT }
218 if i == NX_IS_ELEM_PERSPECTIVE { return NX_DN_UNDERSPEC_CAMERA }
219 if i == NX_IS_ELEM_SHOT_SIZE { return NX_DN_UNDERSPEC_CAMERA }
220 if i == NX_IS_ELEM_CAMERA_MOTIVATION { return NX_DN_UNDERSPEC_CAMERA }
221 if i == NX_IS_ELEM_BODY_ARCHETYPE { return NX_DN_UNDERSPEC_BODY_ARCHETYPE }
222 return NX_DN_UNDERSPEC_NONE
223 }
224 i = i + 1
225 }
226 return NX_DN_UNDERSPEC_NONE
227}
228
229// ===== Apply to DirectorsNote ======================================
230//
231// After aggregation, push the result back onto the DirectorsNote so
232// downstream services (auto-fix, exemplar memory, trend log) read
233// the tier directly from the envelope they already carry.
234
235func nx_is_apply_to_dn(r: *SurvivalReport, dn: *DirectorsNote) -> nx_int {
236 dn.preflight_tier = r.preflight_tier
237 if r.preflight_tier == NX_PFT_BROKEN {
238 dn.underspec_code = nx_is_first_missing_underspec(r)
239 } else {
240 dn.underspec_code = NX_DN_UNDERSPEC_NONE
241 }
242 return 0
243}