nx_covenant.nx source
↩ module page · 251 lines · 9291 B
1// nx_covenant.nx -- multi-stakeholder + multi-generational consent.
2//
3// Per META-CARDINAL feedback-regenerative-stewardship-doctrine-captain-moroni:
4// the legal-and-relational substrate where regenerative intentions become
5// regenerative actions without harm. Composes: landowner consent +
6// Indigenous Free Prior and Informed Consent (FPIC) per UN Declaration
7// on the Rights of Indigenous Peoples + Indigenous Data Sovereignty +
8// CARE Principles + watershed rights + regulatory compliance + neighbor
9// relationships + future-inheritor obligations.
10//
11// V1 ships sealed enums of stakeholder classes + consent states +
12// covenant lifecycle + revocation handling. Per [[feedback-user-owns-
13// every-bit]]: every consent is operator-scope-bounded + time-bounded
14// + revocable.
15
16import "nx_syscalls.nx"
17import "nx_tier.nx"
18
19// ===== Sealed enum: NxStakeholderClass ============================
20//
21// Per regenerative-stewardship roadmap ยง2.8 -- the canonical stakeholder
22// classes the substrate recognizes for multi-stakeholder consent.
23
24const NX_SH_LANDOWNER: nx_int = 0
25const NX_SH_INDIGENOUS_NATION: nx_int = 1 // requires FPIC
26const NX_SH_DOWNSTREAM_WATER_USER: nx_int = 2
27const NX_SH_REGULATORY_BODY: nx_int = 3
28const NX_SH_NEIGHBOR: nx_int = 4
29const NX_SH_FUTURE_INHERITOR: nx_int = 5 // multi-generational
30const NX_SH_OPERATOR: nx_int = 6 // the primary actor
31const NX_SH_FAMILY_MEMBER: nx_int = 7
32const NX_SH_COMMUNITY_COUNCIL: nx_int = 8
33const NX_SH_TRUSTED_ADVISOR: nx_int = 9 // counsel / ecologist / etc.
34const NX_SH_N_CLASSES: nx_int = 10
35
36// ===== Sealed enum: NxConsentState ================================
37
38const NX_CN_PENDING: nx_int = 0
39const NX_CN_GRANTED: nx_int = 1
40const NX_CN_GRANTED_CONDITIONAL: nx_int = 2 // with stipulations
41const NX_CN_DECLINED: nx_int = 3
42const NX_CN_REVOKED: nx_int = 4
43const NX_CN_EXPIRED: nx_int = 5
44const NX_CN_NOT_APPLICABLE: nx_int = 6 // stakeholder doesn't apply here
45const NX_CN_N_STATES: nx_int = 7
46
47// ===== Sealed enum: NxCovenantVerdict =============================
48
49const NX_CV_V_OK_ALL_GRANTED: nx_int = 0
50const NX_CV_V_PENDING_STAKEHOLDERS: nx_int = 1
51const NX_CV_V_BLOCKED_DECLINED: nx_int = 2
52const NX_CV_V_FPIC_REQUIRED_MISSING: nx_int = 3 // Indigenous consent missing
53const NX_CV_V_REVOKED: nx_int = 4
54const NX_CV_V_EXPIRED: nx_int = 5
55const NX_CV_V_NULL: nx_int = 6
56const NX_CV_V_INVALID: nx_int = 7
57const NX_CV_V_N: nx_int = 8
58
59// ===== Struct: NxConsentEntry =====================================
60
61struct NxConsentEntry {
62 stakeholder_id: nx_int,
63 stakeholder_class: nx_int,
64 state: nx_int,
65 granted_at_us: nx_size,
66 expires_at_us: nx_size,
67 revoked_at_us: nx_size,
68 conditions_hash: nx_size,
69}
70
71const NX_CN_ENT_BYTES: nx_int = 48
72
73// ===== Struct: NxCovenant =========================================
74
75struct NxCovenant {
76 covenant_id: nx_int,
77 project_hash: nx_size,
78 entries: *u8, // array of NxConsentEntry
79 n_entries: nx_int,
80 capacity: nx_int,
81 requires_fpic: nx_int, // 1 if ancestral territory
82 operator_initiated_us: nx_size,
83}
84
85const NX_CV_BYTES: nx_int = 48
86
87func nx_sh_class_is_valid(c: nx_int) -> nx_int {
88 if c < 0 { return 0 }
89 if c >= NX_SH_N_CLASSES { return 0 }
90 return 1
91}
92
93func nx_cn_state_is_valid(s: nx_int) -> nx_int {
94 if s < 0 { return 0 }
95 if s >= NX_CN_N_STATES { return 0 }
96 return 1
97}
98
99func nx_cv_v_is_valid(v: nx_int) -> nx_int {
100 if v < 0 { return 0 }
101 if v >= NX_CV_V_N { return 0 }
102 return 1
103}
104
105func nx_cn_state_is_blocking(s: nx_int) -> nx_int {
106 if s == NX_CN_DECLINED { return 1 }
107 if s == NX_CN_REVOKED { return 1 }
108 if s == NX_CN_EXPIRED { return 1 }
109 return 0
110}
111
112func nx_cn_state_is_satisfied(s: nx_int) -> nx_int {
113 if s == NX_CN_GRANTED { return 1 }
114 if s == NX_CN_GRANTED_CONDITIONAL { return 1 }
115 if s == NX_CN_NOT_APPLICABLE { return 1 }
116 return 0
117}
118
119func nx_sh_class_requires_fpic(c: nx_int) -> nx_int {
120 if c == NX_SH_INDIGENOUS_NATION { return 1 }
121 return 0
122}
123
124func nx_cv_new(covenant_id: nx_int,
125 project_hash: nx_size,
126 capacity: nx_int,
127 requires_fpic: nx_int,
128 now_us: nx_size) -> *NxCovenant {
129 if capacity <= 0 { return 0 as *NxCovenant }
130 let raw: *u8 = sys_mmap(NX_CV_BYTES)
131 let c: *NxCovenant = raw as *NxCovenant
132 c.covenant_id = covenant_id
133 c.project_hash = project_hash
134 c.entries = sys_mmap(capacity * NX_CN_ENT_BYTES)
135 c.n_entries = 0
136 c.capacity = capacity
137 c.requires_fpic = requires_fpic
138 c.operator_initiated_us = now_us
139 return c
140}
141
142func _cv_entry_at(c: *NxCovenant, idx: nx_int) -> *NxConsentEntry {
143 if idx < 0 { return 0 as *NxConsentEntry }
144 if idx >= c.n_entries { return 0 as *NxConsentEntry }
145 let off: nx_int = idx * NX_CN_ENT_BYTES
146 return (c.entries + off) as *NxConsentEntry
147}
148
149func nx_cv_add_stakeholder(c: *NxCovenant,
150 stakeholder_id: nx_int,
151 stakeholder_class: nx_int,
152 now_us: nx_size) -> nx_int {
153 if (c as i64) == 0 { return NX_CV_V_NULL }
154 if nx_sh_class_is_valid(stakeholder_class) == 0 { return NX_CV_V_INVALID }
155 if c.n_entries >= c.capacity { return NX_CV_V_INVALID }
156 let off: nx_int = c.n_entries * NX_CN_ENT_BYTES
157 let e: *NxConsentEntry = (c.entries + off) as *NxConsentEntry
158 e.stakeholder_id = stakeholder_id
159 e.stakeholder_class = stakeholder_class
160 e.state = NX_CN_PENDING
161 e.granted_at_us = 0
162 e.expires_at_us = 0
163 e.revoked_at_us = 0
164 e.conditions_hash = 0
165 c.n_entries = c.n_entries + 1
166 return NX_CV_V_OK_ALL_GRANTED
167}
168
169func nx_cv_set_consent(c: *NxCovenant,
170 stakeholder_id: nx_int,
171 state: nx_int,
172 conditions_hash: nx_size,
173 lifetime_ms: nx_int,
174 now_us: nx_size) -> nx_int {
175 if (c as i64) == 0 { return NX_CV_V_NULL }
176 if nx_cn_state_is_valid(state) == 0 { return NX_CV_V_INVALID }
177 var i: nx_int = 0
178 while i < c.n_entries {
179 let e: *NxConsentEntry = _cv_entry_at(c, i)
180 if e.stakeholder_id == stakeholder_id {
181 e.state = state
182 if state == NX_CN_GRANTED {
183 e.granted_at_us = now_us
184 e.expires_at_us = now_us + (lifetime_ms as nx_size) * 1000
185 }
186 if state == NX_CN_GRANTED_CONDITIONAL {
187 e.granted_at_us = now_us
188 e.expires_at_us = now_us + (lifetime_ms as nx_size) * 1000
189 e.conditions_hash = conditions_hash
190 }
191 if state == NX_CN_REVOKED { e.revoked_at_us = now_us }
192 return NX_CV_V_OK_ALL_GRANTED
193 }
194 i = i + 1
195 }
196 return NX_CV_V_INVALID // stakeholder not registered
197}
198
199func nx_cv_classify(c: *NxCovenant, now_us: nx_size) -> nx_int {
200 if (c as i64) == 0 { return NX_CV_V_NULL }
201 // Check FPIC requirement first
202 if c.requires_fpic == 1 {
203 var found_indigenous: nx_int = 0
204 var found_indigenous_grant: nx_int = 0
205 var i: nx_int = 0
206 while i < c.n_entries {
207 let e: *NxConsentEntry = _cv_entry_at(c, i)
208 if e.stakeholder_class == NX_SH_INDIGENOUS_NATION {
209 found_indigenous = 1
210 if nx_cn_state_is_satisfied(e.state) == 1 {
211 found_indigenous_grant = 1
212 }
213 }
214 i = i + 1
215 }
216 if found_indigenous == 0 { return NX_CV_V_FPIC_REQUIRED_MISSING }
217 if found_indigenous_grant == 0 { return NX_CV_V_FPIC_REQUIRED_MISSING }
218 }
219 // Walk all entries for blocking states
220 var any_pending: nx_int = 0
221 var j: nx_int = 0
222 while j < c.n_entries {
223 let e: *NxConsentEntry = _cv_entry_at(c, j)
224 if e.state == NX_CN_GRANTED {
225 if e.expires_at_us > 0 {
226 if now_us > e.expires_at_us {
227 e.state = NX_CN_EXPIRED
228 }
229 }
230 }
231 if e.state == NX_CN_REVOKED { return NX_CV_V_REVOKED }
232 if e.state == NX_CN_DECLINED { return NX_CV_V_BLOCKED_DECLINED }
233 if e.state == NX_CN_EXPIRED { return NX_CV_V_EXPIRED }
234 if e.state == NX_CN_PENDING { any_pending = 1 }
235 j = j + 1
236 }
237 if any_pending == 1 { return NX_CV_V_PENDING_STAKEHOLDERS }
238 return NX_CV_V_OK_ALL_GRANTED
239}
240
241func nx_cv_count_by_class(c: *NxCovenant, class_id: nx_int) -> nx_int {
242 if (c as i64) == 0 { return 0 }
243 var count: nx_int = 0
244 var i: nx_int = 0
245 while i < c.n_entries {
246 let e: *NxConsentEntry = _cv_entry_at(c, i)
247 if e.stakeholder_class == class_id { count = count + 1 }
248 i = i + 1
249 }
250 return count
251}