nx_treaty.nx source
↩ module page · 283 lines · 11879 B
1// nx_treaty.nx -- bilateral cooperative resource agreement.
2//
3// THE PARTNERSHIP PRIMITIVE. Per user 2026-05-19: "partnering with
4// steam to improve things like vram usage, disk space usage." A
5// treaty is a declarative, breachable agreement between two parties
6// to share a contested resource on agreed terms. Parties may be:
7// - native cell + native cell (intra-Nishi negotiation)
8// - native cell + foreign symbiote (Nishi + Steam-hosted NMS)
9// - organism + symbiote (whole-Nishi-ecosystem + foreign-program)
10//
11// The structural EXCEED-axis vs OS-level resource limits (cgroups,
12// Job Objects, RLIMIT_AS): those are UNILATERAL ceilings imposed by
13// the host. A treaty is BILATERAL -- both parties consent to share
14// terms and either can renegotiate when conditions change. This is
15// the only structurally honest way to integrate a foreground game
16// with a foreground background-inference workload on the same RTX
17// 5080: they negotiate VRAM share dynamically, not fight over it.
18//
19// Composes:
20// nx_budget -- party budgets supply the negotiation basis
21// nx_attention_class -- treaty priority cap (treaty can only
22// require yield UP the priority hierarchy,
23// never down -- a foreground party can't
24// agree to yield to a background party)
25// nx_symbiote -- foreign-party state + observed consumption
26// nx_evict_journal -- proposals, acceptances, breaches logged
27// nx_organism -- container that holds N treaties across
28// all member pairs
29//
30// V1 ships pairwise treaties only. Multi-party treaties (e.g.,
31// {organism, Steam-NMS, OBS-recorder} all agreeing to share 12 GB
32// VRAM with weights 60/30/10) are decomposable into pairwise treaties
33// for V1; a multi-party primitive is queued.
34//
35// Gap list (V1 honest perf verdict):
36// - bilateral only (multi-party decomposes)
37// - no expiration time (treaties last until breach or release)
38// - no automatic renegotiation when budgets change
39// - breach detection is observation-window only (caller invokes
40// nx_treaty_check_breach; no background monitor in V1)
41//
42// genealogy_id: international_treaty_law + biology_mutualism +
43// cardinal_2026-05-19_partnership_not_throttle
44// lineage_id: substrate_treaty_v1
45//
46// nx_safety_envelope:
47// intended_use: "Bilateral cooperative resource share
48// agreement between two ecosystem members"
49// sil_target: SIL2
50// evidence: [shares_sum_to_unity, breach_observable,
51// priority_axiom_enforced]
52// hazard_register: [bug-tape-treaty-priority-inversion,
53// bug-tape-treaty-stale-after-budget-change]
54// verdict: NOT_YET_EVALUATED
55
56import "nx_syscalls.nx"
57import "nx_tier.nx"
58import "nx_budget.nx"
59import "nx_attention_class.nx"
60import "nx_evict_journal.nx"
61const NX_MAGIC_1024: i64 = 1024
62
63// ===== Sealed enum: NxTreatyState ================================
64
65const NX_TR_PROPOSED: nx_int = 0 // a proposed; b has not accepted
66const NX_TR_ACTIVE: nx_int = 1 // both parties agreed; in force
67const NX_TR_BREACHED: nx_int = 2 // one party violated; need renegotiate
68const NX_TR_RELEASED: nx_int = 3 // mutually dissolved
69const NX_TR_N_STATES: nx_int = 4
70
71// ===== Sealed enum: NxTreatyVerdict ==============================
72
73const NX_TREATY_OK: nx_int = 0
74const NX_TREATY_ERR_PRIORITY_INVERT: nx_int = 1 // can't agree to yield down-priority
75const NX_TREATY_ERR_NOT_PROPOSED: nx_int = 2
76const NX_TREATY_ERR_NOT_ACTIVE: nx_int = 3
77const NX_TREATY_ERR_SHARES_INVALID: nx_int = 4 // a + b != 1024 (Q10 unity)
78const NX_TREATY_ERR_BREACHED: nx_int = 5
79const NX_TREATY_ERR_RELEASED: nx_int = 6
80
81// ===== Struct: NxTreaty ==========================================
82//
83// a_id / b_id are cell_id or pid (caller-defined, just for forensics).
84// a_class / b_class are NxAttentionClass values. ram_share_a_q10 and
85// vram_share_a_q10 are Q10 fractions; b's shares = 1024 - a's.
86//
87// breach_at_overshoot_q10 is the threshold: if either party's
88// observed consumption exceeds their share by this margin, treaty
89// is BREACHED and arbiter must renegotiate. Q10 1024 = exact share;
90// Q10 1126 = 10% overshoot tolerance.
91
92struct NxTreaty {
93 treaty_id: nx_int,
94 a_id: nx_int,
95 a_class: nx_int,
96 b_id: nx_int,
97 b_class: nx_int,
98 ram_share_a_q10: nx_int,
99 vram_share_a_q10: nx_int,
100 breach_at_overshoot_q10: nx_int,
101 state: nx_int,
102 breach_count: nx_int,
103 last_state_change_us: nx_size,
104}
105
106// Default 10% overshoot tolerance before declaring breach.
107const NX_TREATY_DEFAULT_BREACH_Q10: nx_int = 1126
108
109// ===== nx_tr_state_is_valid =====================================
110
111func nx_tr_state_is_valid(s: nx_int) -> nx_int {
112 if s < 0 { return 0 }
113 if s >= NX_TR_N_STATES { return 0 }
114 return 1
115}
116
117// ===== nx_treaty_propose =========================================
118//
119// Party A proposes terms. Returns OK or one of the err verdicts.
120// Priority axiom: A cannot propose to yield priority DOWN the
121// hierarchy -- e.g., foreground game cannot agree to surrender VRAM
122// to a background inference cell. That would be priority inversion.
123// Treaties either share equal-priority resources or yield UP only.
124
125func nx_treaty_propose(treaty_id: nx_int,
126 a_id: nx_int, a_class: nx_int,
127 b_id: nx_int, b_class: nx_int,
128 ram_share_a_q10: nx_int,
129 vram_share_a_q10: nx_int,
130 now_us: nx_size) -> *NxTreaty {
131 // Priority axiom check
132 let a_prio: nx_int = nx_ac_priority(a_class)
133 let b_prio: nx_int = nx_ac_priority(b_class)
134 // a is HIGHER priority (lower numeric) than b -- agreeing to a
135 // share where b gets MORE than a would be priority inversion.
136 // ram_share_a < 512 means a gets less than half.
137 if a_prio < b_prio {
138 if ram_share_a_q10 < 512 { return (0 as i64) as *NxTreaty }
139 if vram_share_a_q10 < 512 { return (0 as i64) as *NxTreaty }
140 }
141 if ram_share_a_q10 < 0 { return (0 as i64) as *NxTreaty }
142 if ram_share_a_q10 > NX_MAGIC_1024 { return (0 as i64) as *NxTreaty }
143 if vram_share_a_q10 < 0 { return (0 as i64) as *NxTreaty }
144 if vram_share_a_q10 > NX_MAGIC_1024 { return (0 as i64) as *NxTreaty }
145
146 let t: *NxTreaty = (sys_mmap(88)) as *NxTreaty
147 t.treaty_id = treaty_id
148 t.a_id = a_id
149 t.a_class = a_class
150 t.b_id = b_id
151 t.b_class = b_class
152 t.ram_share_a_q10 = ram_share_a_q10
153 t.vram_share_a_q10 = vram_share_a_q10
154 t.breach_at_overshoot_q10 = NX_TREATY_DEFAULT_BREACH_Q10
155 t.state = NX_TR_PROPOSED
156 t.breach_count = 0
157 t.last_state_change_us = now_us
158 return t
159}
160
161// ===== nx_treaty_accept ==========================================
162//
163// Party B accepts the proposal. Transitions PROPOSED -> ACTIVE.
164
165func nx_treaty_accept(t: *NxTreaty, now_us: nx_size) -> nx_int {
166 if t.state != NX_TR_PROPOSED { return NX_TREATY_ERR_NOT_PROPOSED }
167 t.state = NX_TR_ACTIVE
168 t.last_state_change_us = now_us
169 return NX_TREATY_OK
170}
171
172// ===== nx_treaty_party_share_q10 =================================
173//
174// Returns the share fraction owed to the given party_id for the
175// given resource kind. Returns -1 if party_id is not in the treaty.
176
177func nx_treaty_party_share_q10(t: *NxTreaty, party_id: nx_int, kind: nx_int) -> nx_int {
178 if t.state != NX_TR_ACTIVE { return -1 }
179 if party_id == t.a_id {
180 if kind == NX_RES_RAM { return t.ram_share_a_q10 }
181 if kind == NX_RES_VRAM { return t.vram_share_a_q10 }
182 return -1
183 }
184 if party_id == t.b_id {
185 if kind == NX_RES_RAM { return NX_MAGIC_1024 - t.ram_share_a_q10 }
186 if kind == NX_RES_VRAM { return NX_MAGIC_1024 - t.vram_share_a_q10 }
187 return -1
188 }
189 return -1
190}
191
192// ===== nx_treaty_check_breach ====================================
193//
194// Given the contested pool size and each party's observed consumption,
195// returns 1 if either party has exceeded its share by more than the
196// breach threshold; otherwise 0. State auto-transitions to BREACHED
197// when breach is detected. breach_count increments on each detected
198// breach so the integration layer can spot persistent violators.
199
200func nx_treaty_check_breach(t: *NxTreaty,
201 pool_bytes: nx_size,
202 a_observed: nx_size,
203 b_observed: nx_size,
204 kind: nx_int,
205 now_us: nx_size) -> nx_int {
206 if t.state != NX_TR_ACTIVE { return 0 }
207 if pool_bytes <= 0 { return 0 }
208
209 // Compute each party's quota in bytes.
210 var a_share: nx_int = 0
211 if kind == NX_RES_RAM { a_share = t.ram_share_a_q10 }
212 if kind == NX_RES_VRAM { a_share = t.vram_share_a_q10 }
213 let b_share: nx_int = NX_MAGIC_1024 - a_share
214 let a_quota_bytes: nx_size = ((pool_bytes as i64) * a_share / NX_MAGIC_1024) as nx_size
215 let b_quota_bytes: nx_size = ((pool_bytes as i64) * b_share / NX_MAGIC_1024) as nx_size
216
217 // Compute overshoot Q10 for each party.
218 var a_over: nx_int = 0
219 var b_over: nx_int = 0
220 if a_quota_bytes > 0 {
221 a_over = ((a_observed as i64) * NX_MAGIC_1024) / (a_quota_bytes as i64)
222 }
223 if b_quota_bytes > 0 {
224 b_over = ((b_observed as i64) * NX_MAGIC_1024) / (b_quota_bytes as i64)
225 }
226 if a_over > t.breach_at_overshoot_q10 {
227 t.state = NX_TR_BREACHED
228 t.breach_count = t.breach_count + 1
229 t.last_state_change_us = now_us
230 return 1
231 }
232 if b_over > t.breach_at_overshoot_q10 {
233 t.state = NX_TR_BREACHED
234 t.breach_count = t.breach_count + 1
235 t.last_state_change_us = now_us
236 return 1
237 }
238 return 0
239}
240
241// ===== nx_treaty_release =========================================
242//
243// Mutual dissolution. Either party may invoke; sets state to RELEASED.
244// A released treaty stays in the journal for forensics but does not
245// govern resource allocation.
246
247func nx_treaty_release(t: *NxTreaty, now_us: nx_size) -> nx_int {
248 if t.state == NX_TR_RELEASED { return NX_TREATY_OK }
249 t.state = NX_TR_RELEASED
250 t.last_state_change_us = now_us
251 return NX_TREATY_OK
252}
253
254// ===== nx_treaty_renegotiate_shares ==============================
255//
256// Caller updates the share Q10 values mid-treaty (e.g., NMS texture
257// quality dropped from Ultra to High so it asks for less VRAM; our
258// inference cell can now have a bigger share). Resets state to
259// PROPOSED so the counterparty must re-accept; the breach_count is
260// preserved so persistent breachers don't escape via renegotiation.
261
262func nx_treaty_renegotiate_shares(t: *NxTreaty,
263 ram_share_a_q10: nx_int,
264 vram_share_a_q10: nx_int,
265 now_us: nx_size) -> nx_int {
266 if t.state == NX_TR_RELEASED { return NX_TREATY_ERR_RELEASED }
267 if ram_share_a_q10 < 0 { return NX_TREATY_ERR_SHARES_INVALID }
268 if ram_share_a_q10 > NX_MAGIC_1024 { return NX_TREATY_ERR_SHARES_INVALID }
269 if vram_share_a_q10 < 0 { return NX_TREATY_ERR_SHARES_INVALID }
270 if vram_share_a_q10 > NX_MAGIC_1024 { return NX_TREATY_ERR_SHARES_INVALID }
271 t.ram_share_a_q10 = ram_share_a_q10
272 t.vram_share_a_q10 = vram_share_a_q10
273 t.state = NX_TR_PROPOSED
274 t.last_state_change_us = now_us
275 return NX_TREATY_OK
276}
277
278// ===== nx_treaty_is_active =======================================
279
280func nx_treaty_is_active(t: *NxTreaty) -> nx_int {
281 if t.state == NX_TR_ACTIVE { return 1 }
282 return 0
283}