nx_plan_svc.nx source
↩ module page · 133 lines · 5336 B
1// nx_plan_svc.nx -- PRODUCTION-PLAN SERVICE FACADE. The fourth organ on the
2// nx_service base, and the one that answers the operator's actual question:
3// "help us get a plan on what we need to do." One call takes a product
4// concept and returns the readiness score, the single next gap in kill-order,
5// the concrete action to close it, and whether what remains is a broken
6// concept or just paperwork.
7//
8// This is the recombination layer -- it composes the ingredient, jurisdiction,
9// formulation and economics libraries through nx_prodready into one plan. Four
10// facades now share the nx_service base (go-to-market, lab-science, QC, plan).
11//
12// USAGE: nx_plan_svc <verb> [args...]
13// describe
14// assess <mask> <market> <format> <retail_cents> <margin_permil>
15// <servings> <max_units> <identity> <gmp> <claims> <coa>
16// mask = bitmask of ingredient ids (bit i => ingredient i present)
17// market = SJ_* (0=US 1=EAEU/Belarus ...)
18// format = 1 capsule, 2 powder
19// the last four are 0/1 operator attestations
20//
21// Every number comes from the gated nx_prodready engine; this facade only
22// shapes the plan into JSON.
23//
24// genealogy_id: supplement_gtm + service_infrastructure
25
26import "nx_syscalls.nx"
27import "nx_service.nx"
28import "nx_grounding.nx"
29import "nx_supp_ingredient.nx"
30import "nx_supp_jurisdiction.nx"
31import "nx_prodready.nx"
32const PLAN_MAGIC_8192: i64 = 8192
33
34const PLAN_SVC: *u8 = "plan" as *u8
35
36// ===== describe =======================================================
37
38func plan_describe(j: *NxJson) -> i64 {
39 nsvc_ok_open(j, PLAN_SVC, "describe" as *u8)
40 nj_kv_str(j, "service" as *u8, "production-readiness plan (recombines all GTM inputs)" as *u8)
41 nj_comma(j)
42 nj_kv_int(j, "verb_count" as *u8, 1)
43 nj_comma(j)
44 nj_kv_int(j, "readiness_dimensions" as *u8, PR_N_DIM)
45 nj_comma(j)
46 nj_key(j, "verbs" as *u8)
47 nj_puts(j, "[" as *u8)
48 nj_puts(j, "{\"verb\":\"assess\",\"args\":[\"mask:int\",\"market:int\",\"format:int\",\"retail_cents:int\",\"margin_permil:int\",\"servings:int\",\"max_units:int\",\"identity:int\",\"gmp:int\",\"claims:int\",\"coa:int\"]}" as *u8)
49 nj_puts(j, "]" as *u8)
50 nsvc_ok_close_g(j, GND_ASSERTED)
51 return 0
52}
53
54// ===== assess: the plan ===============================================
55
56func plan_build(argc: i64, argv: *i64) -> *NxProduct {
57 let p: *NxProduct = nx_product_new()
58 p.ingredient_mask = nsvc_arg_int(argc, argv, 2)
59 p.market = nsvc_arg_int(argc, argv, 3)
60 let fmt: i64 = nsvc_arg_int(argc, argv, 4)
61 if fmt > 0 { p.format = fmt }
62 p.retail_cents = nsvc_arg_int(argc, argv, 5)
63 let mg: i64 = nsvc_arg_int(argc, argv, 6)
64 if mg > 0 { p.target_margin_permil = mg }
65 let sv: i64 = nsvc_arg_int(argc, argv, 7)
66 if sv > 0 { p.servings = sv }
67 let mu: i64 = nsvc_arg_int(argc, argv, 8)
68 if mu > 0 { p.max_units = mu }
69 p.identity_ready = nsvc_arg_int(argc, argv, 9)
70 p.gmp_qualified = nsvc_arg_int(argc, argv, 10)
71 p.claims_reviewed = nsvc_arg_int(argc, argv, 11)
72 p.coa_on_file = nsvc_arg_int(argc, argv, 12)
73 return p
74}
75
76func plan_assess(j: *NxJson, argc: i64, argv: *i64) -> i64 {
77 let p: *NxProduct = plan_build(argc, argv)
78 if p.ingredient_mask == 0 {
79 nsvc_error(j, PLAN_SVC, "assess" as *u8, NSVC_ERR_BAD_ARGS, "empty product: ingredient mask is 0" as *u8)
80 return 0
81 }
82 let gap: i64 = pr_first_gap(p)
83 nsvc_ok_open(j, PLAN_SVC, "assess" as *u8)
84 nj_kv_int(j, "readiness_permil" as *u8, pr_readiness_permil(p))
85 nj_comma(j)
86 nj_kv_int(j, "dimensions_passed" as *u8, pr_dims_passed(p))
87 nj_comma(j)
88 nj_kv_int(j, "dimensions_total" as *u8, PR_N_DIM)
89 nj_comma(j)
90 nj_kv_bool(j, "production_ready" as *u8, pr_is_production_ready(p))
91 nj_comma(j)
92 nj_kv_int(j, "next_gap" as *u8, gap)
93 if gap != PR_READY {
94 nj_comma(j)
95 nj_kv_str(j, "next_gap_name" as *u8, pr_dim_name(gap))
96 nj_comma(j)
97 nj_kv_str(j, "next_action" as *u8, pr_action(gap))
98 }
99 nj_comma(j)
100 nj_kv_int(j, "open_computed_blockers" as *u8, pr_open_computed_blockers(p))
101 nj_comma(j)
102 nj_kv_int(j, "open_attestations" as *u8, pr_open_attestations(p))
103 // If legally blocked, name the offending ingredient -- the precise fix.
104 if gap == PR_LEGAL {
105 let bad: i64 = pr_first_unlawful(p)
106 if bad != SI_INVALID {
107 nj_comma(j)
108 nj_kv_str(j, "unlawful_ingredient" as *u8, si_name(bad))
109 nj_comma(j)
110 nj_kv_int(j, "unlawful_class" as *u8, si_class(bad))
111 }
112 }
113 nsvc_ok_close_g(j, GND_ASSERTED)
114 return 0
115}
116
117// ===== dispatch =======================================================
118
119func plan_dispatch(argc: i64, argv: *i64, j: *NxJson) -> i64 {
120 let verb: *u8 = nsvc_arg(argc, argv, 1)
121 if verb[0] == (0 as u8) { plan_describe(j); return 0 }
122 if nsvc_streq(verb, "describe" as *u8) == 1 { plan_describe(j); return 0 }
123 if nsvc_streq(verb, "assess" as *u8) == 1 { plan_assess(j, argc, argv); return 0 }
124 nsvc_error(j, PLAN_SVC, verb, NSVC_ERR_UNKNOWN_VERB, "unknown verb; call describe for the catalog" as *u8)
125 return 1
126}
127
128func main(argc: i64, argv: *i64) -> i64 {
129 let j: *NxJson = nx_json_new(PLAN_MAGIC_8192)
130 let rc: i64 = plan_dispatch(argc, argv, j)
131 nj_flush(j)
132 return rc
133}