nx_offer_ledger.nx source
↩ module page · 146 lines · 4725 B
1// nx_offer_ledger.nx -- licensing outreach / offer tracker. For each
2// TO_ACQUIRE target (a person/host we want to license), record the agent/contact
3// and track the offer through a state machine:
4//
5// open -> PENDING --send--> SENT --accept--> ACCEPTED
6// \----------------decline---> DECLINED
7//
8// On ACCEPTED the caller closes the loop: reclassify the host OWNED
9// (nx_fetch_rights) + mint a grant (nx_rights_ledger) so the talent becomes
10// product-usable. Respectful + legal: nothing is product-usable until a real
11// accepted offer + license exists. Mirrors the nx_rights_ledger pattern.
12//
13// contact_ref is an id into a contacts store (name/email/agent details = a
14// later rung); here it just carries the link.
15// license_tier: ORIGINAL
16
17import "nx_syscalls.nx"
18import "nx_tier.nx"
19
20const NX_OF_PENDING: nx_int = 0
21const NX_OF_SENT: nx_int = 1
22const NX_OF_ACCEPTED: nx_int = 2
23const NX_OF_DECLINED: nx_int = 3
24const NX_OF_N: nx_int = 4
25
26const NX_OF_OK: nx_int = 0
27const NX_OF_ERR_FULL: nx_int = 1
28const NX_OF_ERR_NOT_FOUND: nx_int = 2
29const NX_OF_ERR_BAD_TRANSITION: nx_int = 3
30
31struct NxOffer {
32 offer_id: nx_int,
33 target_bk: nx_int,
34 contact_ref: nx_int,
35 state: nx_int,
36 opened_us: nx_size,
37 decided_us: nx_size,
38}
39
40struct NxOfferLedger {
41 offers: *NxOffer,
42 capacity: nx_size,
43 count: nx_size,
44}
45
46const NX_OF_BYTES: nx_size = 48
47
48func nx_offer_ledger_new(capacity: nx_size) -> *NxOfferLedger {
49 let l: *NxOfferLedger = (sys_mmap(24)) as *NxOfferLedger
50 l.offers = (sys_mmap(capacity * NX_OF_BYTES)) as *NxOffer
51 l.capacity = capacity
52 l.count = 0
53 return l
54}
55
56func _of_at(l: *NxOfferLedger, idx: nx_size) -> *NxOffer {
57 return (l.offers as i64 + (idx as i64) * NX_OF_BYTES) as *NxOffer
58}
59
60func _of_find(l: *NxOfferLedger, offer_id: nx_int) -> nx_int {
61 var i: nx_size = 0
62 while i < l.count {
63 let o: *NxOffer = _of_at(l, i)
64 if o.offer_id == offer_id { return i as i64 }
65 i = i + 1
66 }
67 return -1
68}
69
70// open a PENDING outreach record for a prospective target (additive).
71func nx_offer_open(l: *NxOfferLedger, offer_id: nx_int, target_bk: nx_int, contact_ref: nx_int, now_us: nx_size) -> nx_int {
72 if l.count >= l.capacity { return NX_OF_ERR_FULL }
73 let o: *NxOffer = _of_at(l, l.count)
74 o.offer_id = offer_id
75 o.target_bk = target_bk
76 o.contact_ref = contact_ref
77 o.state = NX_OF_PENDING
78 o.opened_us = now_us
79 o.decided_us = 0
80 l.count = l.count + 1
81 return NX_OF_OK
82}
83
84// PENDING -> SENT (offer made to the agent/contact).
85func nx_offer_send(l: *NxOfferLedger, offer_id: nx_int, now_us: nx_size) -> nx_int {
86 let idx: nx_int = _of_find(l, offer_id)
87 if idx < 0 { return NX_OF_ERR_NOT_FOUND }
88 let o: *NxOffer = _of_at(l, idx as nx_size)
89 if o.state != NX_OF_PENDING { return NX_OF_ERR_BAD_TRANSITION }
90 o.state = NX_OF_SENT
91 return NX_OF_OK
92}
93
94// SENT -> ACCEPTED (they agreed; caller then mints the license).
95func nx_offer_accept(l: *NxOfferLedger, offer_id: nx_int, now_us: nx_size) -> nx_int {
96 let idx: nx_int = _of_find(l, offer_id)
97 if idx < 0 { return NX_OF_ERR_NOT_FOUND }
98 let o: *NxOffer = _of_at(l, idx as nx_size)
99 if o.state != NX_OF_SENT { return NX_OF_ERR_BAD_TRANSITION }
100 o.state = NX_OF_ACCEPTED
101 o.decided_us = now_us
102 return NX_OF_OK
103}
104
105// PENDING or SENT -> DECLINED.
106func nx_offer_decline(l: *NxOfferLedger, offer_id: nx_int, now_us: nx_size) -> nx_int {
107 let idx: nx_int = _of_find(l, offer_id)
108 if idx < 0 { return NX_OF_ERR_NOT_FOUND }
109 let o: *NxOffer = _of_at(l, idx as nx_size)
110 if o.state == NX_OF_ACCEPTED { return NX_OF_ERR_BAD_TRANSITION }
111 if o.state == NX_OF_DECLINED { return NX_OF_ERR_BAD_TRANSITION }
112 o.state = NX_OF_DECLINED
113 o.decided_us = now_us
114 return NX_OF_OK
115}
116
117func nx_offer_state(l: *NxOfferLedger, offer_id: nx_int) -> nx_int {
118 let idx: nx_int = _of_find(l, offer_id)
119 if idx < 0 { return -1 }
120 let o: *NxOffer = _of_at(l, idx as nx_size)
121 return o.state
122}
123
124// is there an ACCEPTED offer for this target?
125func nx_offer_is_accepted(l: *NxOfferLedger, target_bk: nx_int) -> nx_int {
126 var i: nx_size = 0
127 while i < l.count {
128 let o: *NxOffer = _of_at(l, i)
129 if o.target_bk == target_bk {
130 if o.state == NX_OF_ACCEPTED { return 1 }
131 }
132 i = i + 1
133 }
134 return 0
135}
136
137func nx_offer_count_by_state(l: *NxOfferLedger, state: nx_int) -> nx_int {
138 var hits: nx_int = 0
139 var i: nx_size = 0
140 while i < l.count {
141 let o: *NxOffer = _of_at(l, i)
142 if o.state == state { hits = hits + 1 }
143 i = i + 1
144 }
145 return hits
146}