code wiki / _hdl_build / nx_docportal_policy_gate.nx
nx_docportal_policy_gate.nx source
↩ module page · 125 lines · 8441 B
1// nx_docportal_policy_gate.nx -- MEASURED gate for OWNER USAGE POLICY enforcement (operator: "lawyers or users on
2// any site able to flag how the results of their uploads are managed and whether an ai writer can publish blog posts
3// with the content"). Self-contained (in-process; real seg_store + real AI-blog composer). Proves the owner's flags
4// are honored BY CONSTRUCTION:
5// T1 ai_blog ON -> dp_may(AI_BLOG)=1 (permitted)
6// T2 ai_blog OFF -> dp_may(AI_BLOG)=0 (denied) even though the doc is public + searchable
7// T3 blog publish -> the draft CONTAINS the consented doc, EXCLUDES the non-consented doc (1 doc used)
8// T4 consent withdrawal -> after dp_set_policy turns ai_blog OFF, the doc vanishes from the blog AT ONCE, and the
9// doc bytes are preserved (the amendment never deletes content)
10// T5 search management -> a public doc whose owner did NOT flag pub_search is INVISIBLE to the live
11// store-native search (dss_search query-time consent filter), while a flagged doc IS findable
12// Verdict MEASURED. GREEN iff 5/5. Appends knowledge/status/docportal_policy_gate.log. license_tier: ORIGINAL
13import "nx_docportal_aiblog_lib.nx"
14import "nx_g_puts_lib.nx"
15import "nx_docportal_search_seg.nx" // dss_search: the store-native search referee (tsv emitter retired)
16
17func g_num(v: i64) -> i64 {
18 let bb: *u8 = sys_mmap(28); var m: i64 = v
19 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) }
20 let t: *u8 = sys_mmap(28); var k: i64 = 0
21 if m == 0 { t[0] = 48 as u8; k = 1 }
22 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
23 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0
24}
25func g_w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
26func g_wn(fd: i64, v: i64) -> i64 {
27 let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m }
28 let t: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }
29 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
30 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(fd, bb, k); return 0
31}
32func g_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
33func g_contains(hay: *u8, n: i64, ndl: *u8) -> i64 {
34 let nl: i64 = g_slen(ndl); if nl == 0 { return 0 }
35 var i: i64 = 0
36 while i + nl <= n { var j: i64 = 0; var hit: i64 = 1; while j < nl { if hay[i + j] != ndl[j] { hit = 0; j = nl } else { j = j + 1 } } if hit == 1 { return 1 } i = i + 1 }
37 return 0
38}
39func g_trunc(path: *u8) -> i64 { let fd: i64 = sys_openat_wr(path, 0x1a4); if fd >= 0 { sys_close(fd) } return 0 }
40func g_eq(a: *u8, al: i64, b: *u8, bl: i64) -> i64 { if al != bl { return 0 } var i: i64 = 0; while i < al { if a[i] != b[i] { return 0 } i = i + 1 } return 1 }
41
42func main() -> i64 {
43 g_puts("=== DOCPORTAL POLICY GATE (owner usage flags: public-search + AI-blog publish; enforced by construction) ===\n" as *u8)
44 let dom: *u8 = "dppol" as *u8
45 // deterministic re-runs: clear the derived AI-blog corpus (search has NO derived artifact to clear --
46 // the store is the index, and the query-time consent filter is what T5 measures)
47 let bs: *u8 = sys_mmap(512); dp_blogsrc(dom, bs); g_trunc(bs)
48
49 let tA: *u8 = "TRUSTBLOGMARK Estate planning insight on how a living trust avoids probate in Utah." as *u8
50 let tB: *u8 = "PRIVATEMEMOMARK Notes on the Johnson divorce settlement for internal use only." as *u8
51 let tC: *u8 = "NOSEARCHMARK Internal draft not to be indexed for public search." as *u8
52 let cidA: *i64 = sys_mmap(16) as *i64
53 let cidB: *i64 = sys_mmap(16) as *i64
54 let cidC: *i64 = sys_mmap(16) as *i64
55 // docA: owner cleared it for search AND AI-blog ; docB: search only (NOT AI-blog) ; docC: neither
56 dp_ingest_policy(dom, DP_VIS_PUBLIC, DP_USE_PUB_SEARCH | DP_USE_AI_BLOG, tA, g_slen(tA), cidA)
57 dp_ingest_policy(dom, DP_VIS_PUBLIC, DP_USE_PUB_SEARCH, tB, g_slen(tB), cidB)
58 dp_ingest_policy(dom, DP_VIS_PUBLIC, 0, tC, g_slen(tC), cidC)
59
60 var pass: i64 = 0
61
62 // T1 / T2: the flag governs AI-blog permission
63 let mayA: i64 = dp_may(dom, DP_VIS_PUBLIC, cidA[0], DP_USE_AI_BLOG)
64 let mayB: i64 = dp_may(dom, DP_VIS_PUBLIC, cidB[0], DP_USE_AI_BLOG)
65 var t1: i64 = 0; if mayA == 1 { t1 = 1 } pass = pass + t1
66 g_puts(" T1 ai_blog ON -> permitted: "); if t1 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
67 var t2: i64 = 0; if mayB == 0 { t2 = 1 } pass = pass + t2
68 g_puts(" T2 ai_blog OFF -> denied: "); if t2 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
69
70 // T3: the AI-blog draft includes ONLY consented content
71 let blog: *u8 = sys_mmap(8192); let cnt: *i64 = sys_mmap(16) as *i64
72 let blen: i64 = ab_compose_blog(dom, "Andelin West -- Legal Insights" as *u8, blog, 8192, cnt)
73 var t3: i64 = 0
74 let hasA: i64 = g_contains(blog, blen, "TRUSTBLOGMARK" as *u8)
75 let hasB: i64 = g_contains(blog, blen, "PRIVATEMEMOMARK" as *u8)
76 if hasA == 1 { if hasB == 0 { if cnt[0] == 1 { t3 = 1 } } }
77 pass = pass + t3
78 g_puts(" T3 blog includes consented, excludes non-consented (hasA="); g_num(hasA); g_puts(" hasB="); g_num(hasB); g_puts(" used="); g_num(cnt[0]); g_puts("): ")
79 if t3 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
80
81 // T4: consent withdrawal takes effect at once, and the doc bytes survive the amendment
82 dp_set_policy(dom, DP_VIS_PUBLIC, cidA[0], DP_USE_PUB_SEARCH) // owner turns AI-blog OFF for docA
83 let mayA2: i64 = dp_may(dom, DP_VIS_PUBLIC, cidA[0], DP_USE_AI_BLOG)
84 let blog2: *u8 = sys_mmap(8192); let cnt2: *i64 = sys_mmap(16) as *i64
85 let blen2: i64 = ab_compose_blog(dom, "Andelin West -- Legal Insights" as *u8, blog2, 8192, cnt2)
86 let stillA: i64 = g_contains(blog2, blen2, "TRUSTBLOGMARK" as *u8)
87 let pq: *i64 = sys_mmap(16) as *i64; let lq: *i64 = sys_mmap(16) as *i64
88 var preserved: i64 = 0
89 if dp_read(dom, DP_VIS_PUBLIC, cidA[0], pq, lq) == 1 { if g_eq(pq[0] as *u8, lq[0], tA, g_slen(tA)) == 1 { preserved = 1 } }
90 var t4: i64 = 0
91 if mayA2 == 0 { if stillA == 0 { if preserved == 1 { t4 = 1 } } }
92 pass = pass + t4
93 g_puts(" T4 consent withdrawal live + doc preserved (may="); g_num(mayA2); g_puts(" inblog="); g_num(stillA); g_puts(" preserved="); g_num(preserved); g_puts("): ")
94 if t4 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
95
96 // T5: the owner's search flag controls LIVE findability -- docA (flag ON, marker TRUSTBLOGMARK) must be
97 // found by the store-native search; docC (flags=0, marker NOSEARCHMARK) must be invisible even though its
98 // bytes sit in the SAME public shard (query-time consent filter, not emission-time)
99 let scids: *i64 = sys_mmap(16 * 8) as *i64
100 let sscores: *i64 = sys_mmap(16 * 8) as *i64
101 let qA: *u8 = "trustblogmark" as *u8
102 let nA: i64 = dss_search(dom, qA, g_slen(qA), scids, sscores, 16)
103 var hasAsrc: i64 = 0
104 if nA >= 1 { if scids[0] == cidA[0] { hasAsrc = 1 } }
105 let qC: *u8 = "nosearchmark" as *u8
106 let nC: i64 = dss_search(dom, qC, g_slen(qC), scids, sscores, 16)
107 let hasCsrc: i64 = nC
108 var t5: i64 = 0
109 if hasAsrc == 1 { if hasCsrc == 0 { t5 = 1 } }
110 pass = pass + t5
111 g_puts(" T5 owner search-flag controls live findability (A_found="); g_num(hasAsrc); g_puts(" C_found="); g_num(hasCsrc); g_puts("): ")
112 if t5 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
113
114 g_puts("----\nDOCPORTAL-POLICY rows=5 pass="); g_num(pass); g_puts("\n" as *u8)
115 let lg: i64 = sys_openat_append("knowledge/status/docportal_policy_gate.log" as *u8, 0x1a4)
116 if lg >= 0 {
117 g_w(lg, "DOCPORTAL-POLICY ai_blog_permit="); g_wn(lg, t1); g_w(lg, " ai_blog_deny="); g_wn(lg, t2)
118 g_w(lg, " blog_consent_only="); g_wn(lg, t3); g_w(lg, " withdrawal_live_doc_preserved="); g_wn(lg, t4); g_w(lg, " search_flag_controls="); g_wn(lg, t5)
119 g_w(lg, " rows=5 pass="); g_wn(lg, pass)
120 if pass == 5 { g_w(lg, " verdict=GREEN\n" as *u8) } else { g_w(lg, " verdict=RED\n" as *u8) }
121 sys_close(lg)
122 }
123 if pass == 5 { g_puts("DOCPORTAL-POLICY GREEN (owner usage flags enforced by construction; AI-blog consent-gated + amendable -- measured)\n" as *u8); sys_exit(0); return 0 }
124 g_puts("DOCPORTAL-POLICY RED\n" as *u8); sys_exit(1); return 1
125}