eyeling 1.22.2 → 1.22.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/examples/arcling/README.md +38 -167
  2. package/package.json +2 -3
  3. package/test/examples.test.js +20 -2
  4. package/examples/arcling/calidor/calidor.data.json +0 -79
  5. package/examples/arcling/calidor/calidor.expected.json +0 -94
  6. package/examples/arcling/calidor/calidor.model.go +0 -612
  7. package/examples/arcling/calidor/calidor.spec.md +0 -166
  8. package/examples/arcling/delfour/delfour.data.json +0 -67
  9. package/examples/arcling/delfour/delfour.expected.json +0 -88
  10. package/examples/arcling/delfour/delfour.model.go +0 -564
  11. package/examples/arcling/delfour/delfour.spec.md +0 -117
  12. package/examples/arcling/flandor/flandor.data.json +0 -106
  13. package/examples/arcling/flandor/flandor.expected.json +0 -98
  14. package/examples/arcling/flandor/flandor.model.go +0 -655
  15. package/examples/arcling/flandor/flandor.spec.md +0 -155
  16. package/examples/arcling/medior/medior.data.json +0 -96
  17. package/examples/arcling/medior/medior.expected.json +0 -100
  18. package/examples/arcling/medior/medior.model.go +0 -652
  19. package/examples/arcling/medior/medior.spec.md +0 -157
  20. package/test/arcling.test.js +0 -191
  21. /package/examples/output/{auroracare.n3 → auroracare.txt} +0 -0
  22. /package/examples/output/{bmi.n3 → bmi.txt} +0 -0
  23. /package/examples/output/{calidor.n3 → calidor.txt} +0 -0
  24. /package/examples/output/{control-system.n3 → control-system.txt} +0 -0
  25. /package/examples/output/{deep-taxonomy-10.n3 → deep-taxonomy-10.txt} +0 -0
  26. /package/examples/output/{deep-taxonomy-100.n3 → deep-taxonomy-100.txt} +0 -0
  27. /package/examples/output/{deep-taxonomy-1000.n3 → deep-taxonomy-1000.txt} +0 -0
  28. /package/examples/output/{deep-taxonomy-10000.n3 → deep-taxonomy-10000.txt} +0 -0
  29. /package/examples/output/{deep-taxonomy-100000.n3 → deep-taxonomy-100000.txt} +0 -0
  30. /package/examples/output/{delfour.n3 → delfour.txt} +0 -0
  31. /package/examples/output/{digital-product-passport.n3 → digital-product-passport.txt} +0 -0
  32. /package/examples/output/{easter.n3 → easter.txt} +0 -0
  33. /package/examples/output/{flandor.n3 → flandor.txt} +0 -0
  34. /package/examples/output/{french-cities.n3 → french-cities.txt} +0 -0
  35. /package/examples/output/{genetic-algorithm-knapsack.n3 → genetic-algorithm-knapsack.txt} +0 -0
  36. /package/examples/output/{genetic-algorithm.n3 → genetic-algorithm.txt} +0 -0
  37. /package/examples/output/{gps.n3 → gps.txt} +0 -0
  38. /package/examples/output/{interop-demo.n3 → interop-demo.txt} +0 -0
  39. /package/examples/output/{matrix-mechanics.n3 → matrix-mechanics.txt} +0 -0
  40. /package/examples/output/{medior.n3 → medior.txt} +0 -0
  41. /package/examples/output/{n3-speaks-for-itself.n3 → n3-speaks-for-itself.txt} +0 -0
  42. /package/examples/output/{odrl-dpv-ehds-risk-ranked.n3 → odrl-dpv-ehds-risk-ranked.txt} +0 -0
  43. /package/examples/output/{odrl-dpv-healthcare-risk-ranked.n3 → odrl-dpv-healthcare-risk-ranked.txt} +0 -0
  44. /package/examples/output/{odrl-dpv-risk-ranked.n3 → odrl-dpv-risk-ranked.txt} +0 -0
  45. /package/examples/output/{odrl-risk-mitigation.n3 → odrl-risk-mitigation.txt} +0 -0
  46. /package/examples/output/{odrl-risk.n3 → odrl-risk.txt} +0 -0
  47. /package/examples/output/{parcellocker.n3 → parcellocker.txt} +0 -0
  48. /package/examples/output/{pn-junction-tunneling.n3 → pn-junction-tunneling.txt} +0 -0
  49. /package/examples/output/{resto.n3 → resto.txt} +0 -0
  50. /package/examples/output/{sqrt2-cauchy.n3 → sqrt2-cauchy.txt} +0 -0
  51. /package/examples/output/{sqrt2-dedekind.n3 → sqrt2-dedekind.txt} +0 -0
  52. /package/examples/output/{sudoku.n3 → sudoku.txt} +0 -0
  53. /package/examples/output/{transcendental-numbers-stretched.n3 → transcendental-numbers-stretched.txt} +0 -0
  54. /package/examples/output/{transistor-switch.n3 → transistor-switch.txt} +0 -0
  55. /package/examples/output/{wind-turbine.n3 → wind-turbine.txt} +0 -0
@@ -1,652 +0,0 @@
1
- package main
2
-
3
- // Medior is a reference Arcling model for the care-continuity bundle case.
4
- // It derives active needs from coarse signals, selects the lowest-cost eligible
5
- // package, and emits ARC text or a JSON report.
6
-
7
- import (
8
- "crypto/hmac"
9
- "crypto/sha256"
10
- "encoding/hex"
11
- "encoding/json"
12
- "errors"
13
- "fmt"
14
- "os"
15
- "sort"
16
- "strings"
17
- "time"
18
- )
19
-
20
- // Data mirrors the input instance shape from medior.data.json.
21
- type Data struct {
22
- CaseName string `json:"caseName"`
23
- Region string `json:"region"`
24
- Question string `json:"question"`
25
- Timestamps Timestamps `json:"timestamps"`
26
- EvaluationContext EvaluationContext `json:"evaluationContext"`
27
- Thresholds Thresholds `json:"thresholds"`
28
- Signals Signals `json:"signals"`
29
- Budget Budget `json:"budget"`
30
- Packages []Package `json:"packages"`
31
- InsightPolicy InsightPolicy `json:"insightPolicy"`
32
- Integrity Integrity `json:"integrity"`
33
- }
34
-
35
- type Timestamps struct {
36
- CreatedAt string `json:"createdAt"`
37
- ExpiresAt string `json:"expiresAt"`
38
- AuthorizedAt string `json:"authorizedAt"`
39
- DutyPerformedAt string `json:"dutyPerformedAt"`
40
- }
41
-
42
- type EvaluationContext struct {
43
- ScopeDevice string `json:"scopeDevice"`
44
- ScopeEvent string `json:"scopeEvent"`
45
- Purpose string `json:"purpose"`
46
- ProhibitedReusePurpose string `json:"prohibitedReusePurpose"`
47
- }
48
-
49
- type Thresholds struct {
50
- EgfrBelow int `json:"egfrBelow"`
51
- ActiveMedicationCountAtLeast int `json:"activeMedicationCountAtLeast"`
52
- AdmissionsLast180DaysAtLeast int `json:"admissionsLast180DaysAtLeast"`
53
- HoursSinceDischargeAtMost int `json:"hoursSinceDischargeAtMost"`
54
- ActiveNeedCountAtLeast int `json:"activeNeedCountAtLeast"`
55
- }
56
-
57
- type Lab struct {
58
- Egfr int `json:"egfr"`
59
- }
60
-
61
- type Medications struct {
62
- ActiveMedicationCount int `json:"activeMedicationCount"`
63
- }
64
-
65
- type History struct {
66
- AdmissionsLast180Days int `json:"admissionsLast180Days"`
67
- }
68
-
69
- type Discharge struct {
70
- HoursSinceDischarge int `json:"hoursSinceDischarge"`
71
- }
72
-
73
- type Signals struct {
74
- Lab Lab `json:"lab"`
75
- Medications Medications `json:"medications"`
76
- History History `json:"history"`
77
- Discharge Discharge `json:"discharge"`
78
- }
79
-
80
- type Budget struct {
81
- WindowName string `json:"windowName"`
82
- MaxEUR int `json:"maxEUR"`
83
- }
84
-
85
- type Package struct {
86
- ID string `json:"id"`
87
- Name string `json:"name"`
88
- CostEUR int `json:"costEUR"`
89
- Touches int `json:"touches"`
90
- CoversRenalSafetyConcern bool `json:"coversRenalSafetyConcern"`
91
- CoversPolypharmacyRisk bool `json:"coversPolypharmacyRisk"`
92
- CoversReadmissionHistory bool `json:"coversReadmissionHistory"`
93
- CoversRecentDischargeWindow bool `json:"coversRecentDischargeWindow"`
94
- }
95
-
96
- type InsightPolicy struct {
97
- ID string `json:"id"`
98
- Metric string `json:"metric"`
99
- SuggestionPolicy string `json:"suggestionPolicy"`
100
- Type string `json:"type"`
101
- PolicyProfile string `json:"policyProfile"`
102
- PolicyType string `json:"policyType"`
103
- }
104
-
105
- type Integrity struct {
106
- Secret string `json:"secret"`
107
- VerificationMode string `json:"verificationMode"`
108
- }
109
-
110
- type Insight struct {
111
- CreatedAt string `json:"createdAt"`
112
- ExpiresAt string `json:"expiresAt"`
113
- ID string `json:"id"`
114
- Metric string `json:"metric"`
115
- Region string `json:"region"`
116
- ScopeDevice string `json:"scopeDevice"`
117
- ScopeEvent string `json:"scopeEvent"`
118
- SuggestionPolicy string `json:"suggestionPolicy"`
119
- Threshold int `json:"threshold"`
120
- Type string `json:"type"`
121
- }
122
-
123
- type Constraint struct {
124
- LeftOperand string `json:"leftOperand"`
125
- Operator string `json:"operator"`
126
- RightOperand string `json:"rightOperand"`
127
- }
128
-
129
- type Duty struct {
130
- Action string `json:"action"`
131
- Constraint Constraint `json:"constraint"`
132
- }
133
-
134
- type Permission struct {
135
- Action string `json:"action"`
136
- Constraint Constraint `json:"constraint"`
137
- Target string `json:"target"`
138
- }
139
-
140
- type Prohibition struct {
141
- Action string `json:"action"`
142
- Constraint Constraint `json:"constraint"`
143
- Target string `json:"target"`
144
- }
145
-
146
- type Policy struct {
147
- Duty Duty `json:"duty"`
148
- Permission Permission `json:"permission"`
149
- Profile string `json:"profile"`
150
- Prohibition Prohibition `json:"prohibition"`
151
- Type string `json:"type"`
152
- }
153
-
154
- type Envelope struct {
155
- Insight Insight `json:"insight"`
156
- Policy Policy `json:"policy"`
157
- }
158
-
159
- type Derived struct {
160
- RenalSafetyConcern bool `json:"renalSafetyConcern"`
161
- PolypharmacyRisk bool `json:"polypharmacyRisk"`
162
- ReadmissionHistory bool `json:"readmissionHistory"`
163
- RecentDischargeWindow bool `json:"recentDischargeWindow"`
164
- ActiveNeedCount int `json:"activeNeedCount"`
165
- NeedsContinuityBundle bool `json:"needsContinuityBundle"`
166
- EligiblePackageIDs []string `json:"eligiblePackageIds"`
167
- RecommendedPackageID *string `json:"recommendedPackageId"`
168
- RecommendedPackageName *string `json:"recommendedPackageName"`
169
- }
170
-
171
- type IntegrityResult struct {
172
- CanonicalEnvelope string `json:"canonicalEnvelope"`
173
- PayloadHashSHA256 string `json:"payloadHashSHA256"`
174
- EnvelopeHmacSHA256 string `json:"envelopeHmacSHA256"`
175
- VerificationMode string `json:"verificationMode"`
176
- }
177
-
178
- type Answer struct {
179
- Name string `json:"name"`
180
- Region string `json:"region"`
181
- Metric string `json:"metric"`
182
- ActiveNeedCount int `json:"activeNeedCount"`
183
- Threshold int `json:"threshold"`
184
- RecommendedPackage *string `json:"recommendedPackage"`
185
- BudgetCapEUR int `json:"budgetCapEUR"`
186
- PackageCostEUR *int `json:"packageCostEUR"`
187
- PayloadHashSHA256 string `json:"payloadHashSHA256"`
188
- EnvelopeHmacSHA256 string `json:"envelopeHmacSHA256"`
189
- }
190
-
191
- type Checks struct {
192
- PayloadHashMatches bool `json:"payloadHashMatches"`
193
- SignatureVerifies bool `json:"signatureVerifies"`
194
- ThresholdReached bool `json:"thresholdReached"`
195
- ScopeComplete bool `json:"scopeComplete"`
196
- MinimizationRespected bool `json:"minimizationRespected"`
197
- AuthorizationAllowed bool `json:"authorizationAllowed"`
198
- DutyTimely bool `json:"dutyTimely"`
199
- InsurancePricingProhibited bool `json:"insurancePricingProhibited"`
200
- PackageWithinBudget bool `json:"packageWithinBudget"`
201
- PackageCoversAllActiveNeeds bool `json:"packageCoversAllActiveNeeds"`
202
- LowestCostEligiblePackageChosen bool `json:"lowestCostEligiblePackageChosen"`
203
- }
204
-
205
- type Result struct {
206
- CaseName string `json:"caseName"`
207
- Derived Derived `json:"derived"`
208
- Envelope Envelope `json:"envelope"`
209
- Integrity IntegrityResult `json:"integrity"`
210
- Answer Answer `json:"answer"`
211
- ReasonWhy []string `json:"reasonWhy"`
212
- Checks Checks `json:"checks"`
213
- AllChecksPass bool `json:"allChecksPass"`
214
- ArcText string `json:"arcText"`
215
- }
216
-
217
- func assertTrue(condition bool, message string) error {
218
- if !condition {
219
- return errors.New(message)
220
- }
221
- return nil
222
- }
223
-
224
- func readJSON(path string) (Data, error) {
225
- var data Data
226
- b, err := os.ReadFile(path)
227
- if err != nil {
228
- return data, err
229
- }
230
- err = json.Unmarshal(b, &data)
231
- return data, err
232
- }
233
-
234
- func parseTime(value string) time.Time {
235
- t, err := time.Parse(time.RFC3339Nano, value)
236
- if err != nil {
237
- panic(err)
238
- }
239
- return t
240
- }
241
-
242
- // stableStringify recursively sorts map keys so the canonical envelope stays
243
- // byte-stable across runs and languages.
244
- func stableStringify(value any) string {
245
- switch v := value.(type) {
246
- case nil:
247
- return "null"
248
- case map[string]any:
249
- keys := make([]string, 0, len(v))
250
- for key := range v {
251
- keys = append(keys, key)
252
- }
253
- sort.Strings(keys)
254
- parts := make([]string, 0, len(keys))
255
- for _, key := range keys {
256
- parts = append(parts, fmt.Sprintf("%s:%s", stableStringify(key), stableStringify(v[key])))
257
- }
258
- return "{" + strings.Join(parts, ",") + "}"
259
- case []any:
260
- parts := make([]string, 0, len(v))
261
- for _, item := range v {
262
- parts = append(parts, stableStringify(item))
263
- }
264
- return "[" + strings.Join(parts, ",") + "]"
265
- default:
266
- b, _ := json.Marshal(v)
267
- return string(b)
268
- }
269
- }
270
-
271
- // canonicalValue converts typed structs into generic JSON-like values before
272
- // stable stringification.
273
- func canonicalValue(value any) any {
274
- b, _ := json.Marshal(value)
275
- var out any
276
- _ = json.Unmarshal(b, &out)
277
- return out
278
- }
279
-
280
- // validateInstance performs the structural checks for the 4-file bundle.
281
- func validateInstance(data Data) error {
282
- if err := assertTrue(data.CaseName != "", "caseName is required"); err != nil {
283
- return err
284
- }
285
- if err := assertTrue(data.Region != "", "region is required"); err != nil {
286
- return err
287
- }
288
- if err := assertTrue(len(data.Packages) > 0, "packages is required"); err != nil {
289
- return err
290
- }
291
- return nil
292
- }
293
-
294
- // countTrue is used for the active-need threshold logic in the spec.
295
- func countTrue(values ...bool) int {
296
- total := 0
297
- for _, value := range values {
298
- if value {
299
- total++
300
- }
301
- }
302
- return total
303
- }
304
-
305
- // The R* helpers map directly to named derivation clauses in medior.spec.md.
306
- func clauseR1RenalSafetyConcern(data Data) bool {
307
- return data.Signals.Lab.Egfr < data.Thresholds.EgfrBelow
308
- }
309
-
310
- func clauseR2PolypharmacyRisk(data Data) bool {
311
- return data.Signals.Medications.ActiveMedicationCount >= data.Thresholds.ActiveMedicationCountAtLeast
312
- }
313
-
314
- func clauseR3ReadmissionHistory(data Data) bool {
315
- return data.Signals.History.AdmissionsLast180Days >= data.Thresholds.AdmissionsLast180DaysAtLeast
316
- }
317
-
318
- func clauseR4RecentDischargeWindow(data Data) bool {
319
- return data.Signals.Discharge.HoursSinceDischarge <= data.Thresholds.HoursSinceDischargeAtMost
320
- }
321
-
322
- func clauseR5ActiveNeedCount(renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow bool) int {
323
- return countTrue(renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow)
324
- }
325
-
326
- func clauseR6NeedsContinuityBundle(data Data, activeNeedCount int) bool {
327
- return activeNeedCount >= data.Thresholds.ActiveNeedCountAtLeast
328
- }
329
-
330
- // deriveInsight produces the minimized care-coordination signal shared with
331
- // the recipient.
332
- func deriveInsight(data Data) Insight {
333
- return Insight{
334
- CreatedAt: data.Timestamps.CreatedAt,
335
- ExpiresAt: data.Timestamps.ExpiresAt,
336
- ID: data.InsightPolicy.ID,
337
- Metric: data.InsightPolicy.Metric,
338
- Region: data.Region,
339
- ScopeDevice: data.EvaluationContext.ScopeDevice,
340
- ScopeEvent: data.EvaluationContext.ScopeEvent,
341
- SuggestionPolicy: data.InsightPolicy.SuggestionPolicy,
342
- Threshold: data.Thresholds.ActiveNeedCountAtLeast,
343
- Type: data.InsightPolicy.Type,
344
- }
345
- }
346
-
347
- // derivePolicy constructs the usage restrictions paired with the insight.
348
- func derivePolicy(data Data) Policy {
349
- return Policy{
350
- Duty: Duty{
351
- Action: "odrl:delete",
352
- Constraint: Constraint{
353
- LeftOperand: "odrl:dateTime",
354
- Operator: "odrl:eq",
355
- RightOperand: data.Timestamps.ExpiresAt,
356
- },
357
- },
358
- Permission: Permission{
359
- Action: "odrl:use",
360
- Constraint: Constraint{
361
- LeftOperand: "odrl:purpose",
362
- Operator: "odrl:eq",
363
- RightOperand: data.EvaluationContext.Purpose,
364
- },
365
- Target: data.InsightPolicy.ID,
366
- },
367
- Profile: data.InsightPolicy.PolicyProfile,
368
- Prohibition: Prohibition{
369
- Action: "odrl:distribute",
370
- Constraint: Constraint{
371
- LeftOperand: "odrl:purpose",
372
- Operator: "odrl:eq",
373
- RightOperand: data.EvaluationContext.ProhibitedReusePurpose,
374
- },
375
- Target: data.InsightPolicy.ID,
376
- },
377
- Type: data.InsightPolicy.PolicyType,
378
- }
379
- }
380
-
381
- // packageCoversAllActiveNeeds checks whether a candidate package addresses every
382
- // active need in this instance.
383
- func packageCoversAllActiveNeeds(pkg Package, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow bool) bool {
384
- return (!renalSafetyConcern || pkg.CoversRenalSafetyConcern) &&
385
- (!polypharmacyRisk || pkg.CoversPolypharmacyRisk) &&
386
- (!readmissionHistory || pkg.CoversReadmissionHistory) &&
387
- (!recentDischargeWindow || pkg.CoversRecentDischargeWindow)
388
- }
389
-
390
- // clauseS1EligiblePackages filters to packages that both fit the budget and
391
- // cover the active needs.
392
- func clauseS1EligiblePackages(data Data, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow bool) []Package {
393
- eligible := make([]Package, 0)
394
- for _, pkg := range data.Packages {
395
- if pkg.CostEUR <= data.Budget.MaxEUR && packageCoversAllActiveNeeds(pkg, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow) {
396
- eligible = append(eligible, pkg)
397
- }
398
- }
399
- sort.Slice(eligible, func(i, j int) bool { return eligible[i].CostEUR < eligible[j].CostEUR })
400
- return eligible
401
- }
402
-
403
- // clauseS2RecommendedPackage applies the tie-breaker: choose the lowest-cost
404
- // eligible package after sorting by cost.
405
- func clauseS2RecommendedPackage(data Data, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow bool) ([]Package, *Package) {
406
- eligible := clauseS1EligiblePackages(data, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow)
407
- if len(eligible) == 0 {
408
- return eligible, nil
409
- }
410
- recommended := eligible[0]
411
- return eligible, &recommended
412
- }
413
-
414
- func clauseG1AuthorizedUse(data Data) bool {
415
- return data.EvaluationContext.Purpose == "care_coordination" && !parseTime(data.Timestamps.AuthorizedAt).After(parseTime(data.Timestamps.ExpiresAt))
416
- }
417
-
418
- func clauseG2InsurancePricingProhibited(data Data) bool {
419
- return data.EvaluationContext.ProhibitedReusePurpose == "insurance_pricing"
420
- }
421
-
422
- func clauseG3DutyTimely(data Data) bool {
423
- return !parseTime(data.Timestamps.DutyPerformedAt).After(parseTime(data.Timestamps.ExpiresAt))
424
- }
425
-
426
- // clauseM1CanonicalEnvelope returns both the structured envelope and the
427
- // deterministic string hashed/signed by the integrity clauses.
428
- func clauseM1CanonicalEnvelope(data Data) (Envelope, string) {
429
- envelope := Envelope{Insight: deriveInsight(data), Policy: derivePolicy(data)}
430
- return envelope, stableStringify(canonicalValue(envelope))
431
- }
432
-
433
- func sha256Hex(text string) string {
434
- sum := sha256.Sum256([]byte(text))
435
- return hex.EncodeToString(sum[:])
436
- }
437
-
438
- func hmacSHA256Hex(secret, text string) string {
439
- mac := hmac.New(sha256.New, []byte(secret))
440
- _, _ = mac.Write([]byte(text))
441
- return hex.EncodeToString(mac.Sum(nil))
442
- }
443
-
444
- func clauseM4MinimizationRespected(insight Insight) bool {
445
- b, _ := json.Marshal(insight)
446
- s := strings.ToLower(string(b))
447
- return !strings.Contains(s, "name") && !strings.Contains(s, "address") && !strings.Contains(s, "ssn") && !strings.Contains(s, "fullrecord") && !strings.Contains(s, "genome")
448
- }
449
-
450
- func clauseM5ScopeComplete(insight Insight) bool {
451
- return insight.ScopeDevice != "" && insight.ScopeEvent != "" && insight.ExpiresAt != ""
452
- }
453
-
454
- func yesNo(value bool) string {
455
- if value {
456
- return "PASS"
457
- }
458
- return "FAIL"
459
- }
460
-
461
- // evaluate computes all derived facts, governance checks, integrity values,
462
- // and presentation fields expected by medior.expected.json.
463
- func evaluate(data Data) (Result, error) {
464
- if err := validateInstance(data); err != nil {
465
- return Result{}, err
466
- }
467
-
468
- renalSafetyConcern := clauseR1RenalSafetyConcern(data)
469
- polypharmacyRisk := clauseR2PolypharmacyRisk(data)
470
- readmissionHistory := clauseR3ReadmissionHistory(data)
471
- recentDischargeWindow := clauseR4RecentDischargeWindow(data)
472
- activeNeedCount := clauseR5ActiveNeedCount(renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow)
473
- needsContinuityBundle := clauseR6NeedsContinuityBundle(data, activeNeedCount)
474
-
475
- envelope, canonicalEnvelope := clauseM1CanonicalEnvelope(data)
476
- payloadHashSHA256 := sha256Hex(canonicalEnvelope)
477
- envelopeHmacSHA256 := hmacSHA256Hex(data.Integrity.Secret, canonicalEnvelope)
478
-
479
- eligible, recommended := clauseS2RecommendedPackage(data, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow)
480
- recommendedID := (*string)(nil)
481
- recommendedName := (*string)(nil)
482
- packageCostEUR := (*int)(nil)
483
- if recommended != nil {
484
- recommendedID = &recommended.ID
485
- recommendedName = &recommended.Name
486
- packageCostEUR = &recommended.CostEUR
487
- }
488
-
489
- checks := Checks{
490
- PayloadHashMatches: payloadHashSHA256 == sha256Hex(canonicalEnvelope),
491
- SignatureVerifies: data.Integrity.VerificationMode == "trustedPrecomputedInput" && envelopeHmacSHA256 == hmacSHA256Hex(data.Integrity.Secret, canonicalEnvelope),
492
- ThresholdReached: needsContinuityBundle,
493
- ScopeComplete: clauseM5ScopeComplete(envelope.Insight),
494
- MinimizationRespected: clauseM4MinimizationRespected(envelope.Insight),
495
- AuthorizationAllowed: clauseG1AuthorizedUse(data),
496
- DutyTimely: clauseG3DutyTimely(data),
497
- InsurancePricingProhibited: clauseG2InsurancePricingProhibited(data),
498
- PackageWithinBudget: recommended != nil && recommended.CostEUR <= data.Budget.MaxEUR,
499
- PackageCoversAllActiveNeeds: recommended != nil && packageCoversAllActiveNeeds(*recommended, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow),
500
- LowestCostEligiblePackageChosen: recommended != nil && recommended.ID == eligible[0].ID,
501
- }
502
-
503
- reasonWhy := []string{
504
- fmt.Sprintf("RenalSafetyConcern holds because eGFR = %d and the threshold is < %d.", data.Signals.Lab.Egfr, data.Thresholds.EgfrBelow),
505
- fmt.Sprintf("PolypharmacyRisk holds because the active medication count is %d and the threshold is ≥ %d.", data.Signals.Medications.ActiveMedicationCount, data.Thresholds.ActiveMedicationCountAtLeast),
506
- fmt.Sprintf("ReadmissionHistory holds because admissionsLast180Days = %d and the threshold is ≥ %d.", data.Signals.History.AdmissionsLast180Days, data.Thresholds.AdmissionsLast180DaysAtLeast),
507
- fmt.Sprintf("RecentDischargeWindow holds because hoursSinceDischarge = %d and the threshold is ≤ %d.", data.Signals.Discharge.HoursSinceDischarge, data.Thresholds.HoursSinceDischargeAtMost),
508
- "The recommendation rule selects the least-cost package that covers every active need and remains within budget.",
509
- func() string {
510
- if recommended != nil {
511
- return fmt.Sprintf("The selected package is \"%s\" with cost €%d, touches=%d.", recommended.Name, recommended.CostEUR, recommended.Touches)
512
- }
513
- return "No eligible package exists within budget."
514
- }(),
515
- fmt.Sprintf("Use is permitted only for purpose \"%s\" and expires at %s.", data.EvaluationContext.Purpose, data.Timestamps.ExpiresAt),
516
- }
517
-
518
- answer := Answer{
519
- Name: data.CaseName,
520
- Region: data.Region,
521
- Metric: data.InsightPolicy.Metric,
522
- ActiveNeedCount: activeNeedCount,
523
- Threshold: data.Thresholds.ActiveNeedCountAtLeast,
524
- RecommendedPackage: recommendedName,
525
- BudgetCapEUR: data.Budget.MaxEUR,
526
- PackageCostEUR: packageCostEUR,
527
- PayloadHashSHA256: payloadHashSHA256,
528
- EnvelopeHmacSHA256: envelopeHmacSHA256,
529
- }
530
-
531
- arcLines := []string{
532
- "=== Answer ===",
533
- fmt.Sprintf("Name: %s", answer.Name),
534
- fmt.Sprintf("Region: %s", answer.Region),
535
- fmt.Sprintf("Metric: %s", answer.Metric),
536
- fmt.Sprintf("Active need count: %d/%d", answer.ActiveNeedCount, answer.Threshold),
537
- fmt.Sprintf("Recommended package: %s", derefString(answer.RecommendedPackage)),
538
- fmt.Sprintf("Budget cap: €%d", answer.BudgetCapEUR),
539
- fmt.Sprintf("Package cost: €%s", derefIntString(answer.PackageCostEUR)),
540
- fmt.Sprintf("Payload SHA-256: %s", answer.PayloadHashSHA256),
541
- fmt.Sprintf("Envelope HMAC-SHA-256: %s", answer.EnvelopeHmacSHA256),
542
- "",
543
- "=== Reason Why ===",
544
- }
545
- arcLines = append(arcLines, reasonWhy...)
546
- arcLines = append(arcLines, "", "=== Check ===")
547
- checkOrder := []struct {
548
- name string
549
- ok bool
550
- }{
551
- {"payloadHashMatches", checks.PayloadHashMatches},
552
- {"signatureVerifies", checks.SignatureVerifies},
553
- {"thresholdReached", checks.ThresholdReached},
554
- {"scopeComplete", checks.ScopeComplete},
555
- {"minimizationRespected", checks.MinimizationRespected},
556
- {"authorizationAllowed", checks.AuthorizationAllowed},
557
- {"dutyTimely", checks.DutyTimely},
558
- {"insurancePricingProhibited", checks.InsurancePricingProhibited},
559
- {"packageWithinBudget", checks.PackageWithinBudget},
560
- {"packageCoversAllActiveNeeds", checks.PackageCoversAllActiveNeeds},
561
- {"lowestCostEligiblePackageChosen", checks.LowestCostEligiblePackageChosen},
562
- }
563
- for _, item := range checkOrder {
564
- arcLines = append(arcLines, fmt.Sprintf("- %s: %s", yesNo(item.ok), item.name))
565
- }
566
-
567
- allChecksPass := checks.PayloadHashMatches && checks.SignatureVerifies && checks.ThresholdReached && checks.ScopeComplete && checks.MinimizationRespected && checks.AuthorizationAllowed && checks.DutyTimely && checks.InsurancePricingProhibited && checks.PackageWithinBudget && checks.PackageCoversAllActiveNeeds && checks.LowestCostEligiblePackageChosen
568
-
569
- return Result{
570
- CaseName: data.CaseName,
571
- Derived: Derived{
572
- RenalSafetyConcern: renalSafetyConcern,
573
- PolypharmacyRisk: polypharmacyRisk,
574
- ReadmissionHistory: readmissionHistory,
575
- RecentDischargeWindow: recentDischargeWindow,
576
- ActiveNeedCount: activeNeedCount,
577
- NeedsContinuityBundle: needsContinuityBundle,
578
- EligiblePackageIDs: func() []string {
579
- ids := make([]string, 0, len(eligible))
580
- for _, pkg := range eligible {
581
- ids = append(ids, pkg.ID)
582
- }
583
- return ids
584
- }(),
585
- RecommendedPackageID: recommendedID,
586
- RecommendedPackageName: recommendedName,
587
- },
588
- Envelope: envelope,
589
- Integrity: IntegrityResult{
590
- CanonicalEnvelope: canonicalEnvelope,
591
- PayloadHashSHA256: payloadHashSHA256,
592
- EnvelopeHmacSHA256: envelopeHmacSHA256,
593
- VerificationMode: data.Integrity.VerificationMode,
594
- },
595
- Answer: answer,
596
- ReasonWhy: reasonWhy,
597
- Checks: checks,
598
- AllChecksPass: allChecksPass,
599
- ArcText: strings.Join(arcLines, "\n"),
600
- }, nil
601
- }
602
-
603
- func derefString(value *string) string {
604
- if value == nil {
605
- return "<nil>"
606
- }
607
- return *value
608
- }
609
-
610
- func derefIntString(value *int) string {
611
- if value == nil {
612
- return "<nil>"
613
- }
614
- return fmt.Sprintf("%d", *value)
615
- }
616
-
617
- // main is the CLI entry point used by the Arcling test runner.
618
- func main() {
619
- inputPath := "medior.data.json"
620
- jsonMode := false
621
- for _, arg := range os.Args[1:] {
622
- if arg == "--json" {
623
- jsonMode = true
624
- } else if !strings.HasPrefix(arg, "--") {
625
- inputPath = arg
626
- }
627
- }
628
-
629
- data, err := readJSON(inputPath)
630
- if err != nil {
631
- fmt.Fprintln(os.Stderr, err)
632
- os.Exit(1)
633
- }
634
-
635
- result, err := evaluate(data)
636
- if err != nil {
637
- fmt.Fprintln(os.Stderr, err)
638
- os.Exit(1)
639
- }
640
-
641
- if jsonMode {
642
- enc := json.NewEncoder(os.Stdout)
643
- enc.SetIndent("", " ")
644
- _ = enc.Encode(result)
645
- } else {
646
- fmt.Println(result.ArcText)
647
- }
648
-
649
- if !result.AllChecksPass {
650
- os.Exit(1)
651
- }
652
- }