eyeling 1.22.0 → 1.22.2

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.
@@ -0,0 +1,166 @@
1
+ # Calidor — ARC Specification
2
+
3
+ ## Status
4
+
5
+ This document is the normative specification for the Calidor case. The file `calidor.model.go` is the reference Go implementation of these clauses. The file `calidor.data.json` is the instance evaluated in this bundle. The file `calidor.expected.json` is the conformance vector for that instance.
6
+
7
+ ## Insight Economy context
8
+
9
+ This case models municipal heatwave support. A household gateway observes local indoor heat stress, local vulnerability signals, and local prepaid-energy stress. Those raw details remain local. The system shares only a narrow, expiring insight that the household qualifies for priority cooling support during the current heat-alert window.
10
+
11
+ The city may use that insight for heatwave response. It may not reuse it for unrelated purposes such as tenant screening.
12
+
13
+ ## Conventions
14
+
15
+ - “iff” means “if and only if”.
16
+ - A clause identifier such as `R1` or `G2` is normative.
17
+ - A conforming implementation may be written in any language, but it shall produce the same derived values and pass/fail outcomes for the supplied instance.
18
+ - The reference implementation in this bundle is written in Go.
19
+ - Input validation is part of the reference model. A malformed instance shall fail before evaluation.
20
+
21
+ ## Vocabulary
22
+
23
+ **V1. Heat alert** is the municipal emergency context.
24
+
25
+ **V2. Unsafe indoor heat** is sustained indoor temperature at or above the configured threshold.
26
+
27
+ **V3. Vulnerability presence** is the existence of at least one local heat-sensitivity or mobility-related flag.
28
+
29
+ **V4. Energy constraint** is insufficient prepaid energy credit to sustain cooling use.
30
+
31
+ **V5. Support package** is a municipal assistance option with a cost and a set of capabilities.
32
+
33
+ **V6. Insight envelope** is the ordered pair `(insight, policy)` together with integrity metadata.
34
+
35
+ ## Input instance
36
+
37
+ **I1.** The municipality is `Calidor`.
38
+
39
+ **I2.** The current heat alert level is `4`.
40
+
41
+ **I3.** The alert threshold is `3`.
42
+
43
+ **I4.** The current indoor temperature is `31.4` °C.
44
+
45
+ **I5.** Unsafe indoor heat requires at least `30.0` °C for at least `6` hours.
46
+
47
+ **I6.** The household has local vulnerability flags.
48
+
49
+ **I7.** Remaining prepaid energy credit is `3.2` EUR.
50
+
51
+ **I8.** Energy constraint holds at or below `5.0` EUR.
52
+
53
+ **I9.** Priority cooling support requires at least `3` active needs.
54
+
55
+ **I10.** The support catalog is the one listed in `calidor.data.json`.
56
+
57
+ ## Derivation clauses
58
+
59
+ **R1. HeatAlertActive.** `HeatAlertActive` holds iff `currentAlertLevel ≥ alertLevelAtLeast`.
60
+
61
+ **R2. UnsafeIndoorHeat.** `UnsafeIndoorHeat` holds iff:
62
+
63
+ 1. `currentIndoorTempC ≥ indoorTempCAtLeast`; and
64
+ 2. `hoursAtOrAboveThreshold ≥ hoursAtOrAboveThresholdAtLeast`.
65
+
66
+ **R3. VulnerabilityPresent.** `VulnerabilityPresent` holds iff the local vulnerability flag list is non-empty.
67
+
68
+ **R4. EnergyConstraint.** `EnergyConstraint` holds iff `remainingPrepaidCreditEur ≤ energyCreditEurAtMost`.
69
+
70
+ **R5. ActiveNeedCount.** `ActiveNeedCount` is the number of true predicates among:
71
+
72
+ - `HeatAlertActive`
73
+ - `UnsafeIndoorHeat`
74
+ - `VulnerabilityPresent`
75
+ - `EnergyConstraint`
76
+
77
+ **R6. PriorityCoolingSupportNeeded.** `PriorityCoolingSupportNeeded` holds iff `ActiveNeedCount ≥ minimumActiveNeedCount`.
78
+
79
+ **R7. RequiredCapabilities.** The required capability set is formed as follows:
80
+
81
+ 1. if `HeatAlertActive` and `UnsafeIndoorHeat`, include `cooling_kit`;
82
+ 2. if `VulnerabilityPresent`, include `welfare_check` and `transport`;
83
+ 3. if `EnergyConstraint`, include `bill_credit`.
84
+
85
+ The resulting set is sorted lexically for reporting.
86
+
87
+ **R8. EligiblePackage(p).** For a package `p`, `EligiblePackage(p)` holds iff:
88
+
89
+ 1. `p.costEur ≤ maxPackageCostEur`; and
90
+ 2. `p.capabilities` cover every entry in `RequiredCapabilities`.
91
+
92
+ **R9. RecommendedPackage.** `RecommendedPackage` is the eligible package with minimum `costEur`, breaking ties lexically by `id`.
93
+
94
+ ## Governance clauses
95
+
96
+ **G1. AuthorizedUse.** `AuthorizedUse` holds iff:
97
+
98
+ 1. the requested action is `odrl:use`;
99
+ 2. the requested purpose is `heatwave_response`; and
100
+ 3. the authorization time is not later than the expiry time.
101
+
102
+ **G2. TenantScreeningProhibited.** `TenantScreeningProhibited` holds iff the policy prohibits distribution for purpose `tenant_screening`.
103
+
104
+ **G3. DutyTimely.** `DutyTimely` holds iff the duty-performance time is not later than the expiry time.
105
+
106
+ ## Integrity and minimization clauses
107
+
108
+ **M1. CanonicalEnvelope.** The canonical envelope string is the JSON serialization of the ordered pair `(insight, policy)` with keys emitted in this exact sequence:
109
+
110
+ - insight: `createdAt`, `expiresAt`, `id`, `metric`, `municipality`, `scopeDevice`, `scopeEvent`, `supportPolicy`, `threshold`, `type`
111
+ - policy: `duty`, `permission`, `profile`, `prohibition`, `type`
112
+
113
+ For this case, `threshold` is serialized lexically as `3.0` rather than `3`, because the integrity vector is defined over those exact envelope bytes.
114
+
115
+ **M2. PayloadHashMatches.** `PayloadHashMatches` holds iff the model-computed SHA-256 of `CanonicalEnvelope` equals the expected SHA-256 value recorded in the conformance vector.
116
+
117
+ **M3. SignatureVerifies.** `SignatureVerifies` holds iff the model-computed HMAC-SHA-256 of `CanonicalEnvelope` equals the expected HMAC value recorded in the conformance vector.
118
+
119
+ **M4. MinimizationRespected.** `MinimizationRespected` holds iff the serialized insight contains none of the forbidden terms:
120
+
121
+ - `heat_sensitive_condition`
122
+ - `mobility_limitation`
123
+ - `credit`
124
+ - `meter_trace`
125
+
126
+ **M5. ScopeComplete.** `ScopeComplete` holds iff the insight contains `scopeDevice`, `scopeEvent`, and `expiresAt`.
127
+
128
+ ## Output contract
129
+
130
+ **O1. Answer.** A conforming renderer shall expose:
131
+
132
+ - the main recommendation sentence
133
+ - recommended package
134
+ - required capabilities
135
+ - payload hash
136
+ - envelope HMAC
137
+
138
+ **O2. Reason Why.** A conforming renderer shall explain that raw household heat, vulnerability, and prepaid-energy details remain local and that only a narrow heatwave-response insight is shared.
139
+
140
+ **O3. Check.** A conforming renderer shall expose a named yes/no or PASS/FAIL outcome for each of:
141
+
142
+ - `signatureVerifies`
143
+ - `payloadHashMatches`
144
+ - `minimizationRespected`
145
+ - `scopeComplete`
146
+ - `authorizationAllowed`
147
+ - `heatAlertActive`
148
+ - `unsafeIndoorHeat`
149
+ - `priorityCoolingSupportNeeded`
150
+ - `recommendedPackageEligible`
151
+ - `dutyTimingConsistent`
152
+ - `tenantScreeningProhibited`
153
+
154
+ ## Reference outcome for this instance
155
+
156
+ For the supplied instance:
157
+
158
+ - `HeatAlertActive = true`
159
+ - `UnsafeIndoorHeat = true`
160
+ - `VulnerabilityPresent = true`
161
+ - `EnergyConstraint = true`
162
+ - `ActiveNeedCount = 4`
163
+ - `PriorityCoolingSupportNeeded = true`
164
+ - `RecommendedPackage = "Calidor Priority Cooling Bundle"`
165
+
166
+ The expected ARC report and integrity values are recorded in `calidor.expected.json`.
@@ -1,5 +1,4 @@
1
1
  {
2
- "$schema": "./delfour.instance.schema.json",
3
2
  "caseName": "Delfour",
4
3
  "retailer": "Delfour",
5
4
  "question": "Is the Delfour self-scanner allowed to use a neutral shopping insight for shopping assistance, and if so what lower-sugar alternative should it suggest?",
@@ -1,5 +1,10 @@
1
1
  package main
2
2
 
3
+ // Delfour is a reference Arcling model written as a small CLI program.
4
+ // It reads delfour.data.json, derives the neutral shopping insight,
5
+ // computes the canonical envelope/hash/HMAC values, and emits either
6
+ // ARC text or a JSON result object.
7
+
3
8
  import (
4
9
  "crypto/hmac"
5
10
  "crypto/sha256"
@@ -13,6 +18,7 @@ import (
13
18
  "time"
14
19
  )
15
20
 
21
+ // Data mirrors the input instance shape from delfour.data.json.
16
22
  type Data struct {
17
23
  CaseName string `json:"caseName"`
18
24
  Retailer string `json:"retailer"`
@@ -77,6 +83,7 @@ type Integrity struct {
77
83
  VerificationMode string `json:"verificationMode"`
78
84
  }
79
85
 
86
+ // Insight is the minimized payload shared with the retailer.
80
87
  type Insight struct {
81
88
  CreatedAt string `json:"createdAt"`
82
89
  ExpiresAt string `json:"expiresAt"`
@@ -191,6 +198,7 @@ func readJSON(path string) (Data, error) {
191
198
  return data, err
192
199
  }
193
200
 
201
+ // validate performs the structural checks that used to live in JSON Schema.
194
202
  func validate(data Data) error {
195
203
  if err := must(data.CaseName != "", "caseName is required"); err != nil {
196
204
  return err
@@ -234,6 +242,7 @@ func validate(data Data) error {
234
242
  return nil
235
243
  }
236
244
 
245
+ // parseTime accepts RFC3339Nano timestamps from the case instance.
237
246
  func parseTime(s string) time.Time {
238
247
  t, err := time.Parse(time.RFC3339Nano, s)
239
248
  if err != nil {
@@ -242,6 +251,7 @@ func parseTime(s string) time.Time {
242
251
  return t
243
252
  }
244
253
 
254
+ // findProduct resolves the scanned or recommended product by its catalog id.
245
255
  func findProduct(data Data, id string) *Product {
246
256
  for i := range data.Catalog {
247
257
  if data.Catalog[i].ID == id {
@@ -251,6 +261,7 @@ func findProduct(data Data, id string) *Product {
251
261
  return nil
252
262
  }
253
263
 
264
+ // deriveInsight strips the household condition down to the neutral shopping insight.
254
265
  func deriveInsight(data Data) Insight {
255
266
  return Insight{
256
267
  CreatedAt: data.Timestamps.CreatedAt,
@@ -266,6 +277,7 @@ func deriveInsight(data Data) Insight {
266
277
  }
267
278
  }
268
279
 
280
+ // derivePolicy builds the companion ODRL-style policy used for governance checks.
269
281
  func derivePolicy(data Data) Policy {
270
282
  return Policy{
271
283
  Duty: Duty{
@@ -299,6 +311,8 @@ func derivePolicy(data Data) Policy {
299
311
  }
300
312
  }
301
313
 
314
+ // canonicalEnvelope returns the exact byte string used for the integrity vector.
315
+ // The field order and the lexical form of threshold (10.0) are intentional.
302
316
  func canonicalEnvelope(insight Insight, policy Policy) string {
303
317
  return fmt.Sprintf(
304
318
  "{\"insight\":{\"createdAt\":\"%s\",\"expiresAt\":\"%s\",\"id\":\"%s\",\"metric\":\"%s\",\"retailer\":\"%s\",\"scopeDevice\":\"%s\",\"scopeEvent\":\"%s\",\"suggestionPolicy\":\"%s\",\"threshold\":10.0,\"type\":\"%s\"},\"policy\":{\"duty\":{\"action\":\"%s\",\"constraint\":{\"leftOperand\":\"%s\",\"operator\":\"%s\",\"rightOperand\":\"%s\"}},\"permission\":{\"action\":\"%s\",\"constraint\":{\"leftOperand\":\"%s\",\"operator\":\"%s\",\"rightOperand\":\"%s\"},\"target\":\"%s\"},\"profile\":\"%s\",\"prohibition\":{\"action\":\"%s\",\"constraint\":{\"leftOperand\":\"%s\",\"operator\":\"%s\",\"rightOperand\":\"%s\"},\"target\":\"%s\"},\"type\":\"%s\"}}",
@@ -348,6 +362,8 @@ func yesNo(v bool) string {
348
362
  return "no"
349
363
  }
350
364
 
365
+ // evaluate runs the full Arcling pipeline: derive facts, select the recommendation,
366
+ // build the envelope, verify integrity values, and render the final report.
351
367
  func evaluate(data Data) (Result, error) {
352
368
  var result Result
353
369
  if err := validate(data); err != nil {
@@ -508,6 +524,8 @@ func evaluate(data Data) (Result, error) {
508
524
  return result, nil
509
525
  }
510
526
 
527
+ // main is a tiny CLI wrapper around evaluate. It defaults to delfour.data.json,
528
+ // prints ARC text, and switches to JSON output when --json is supplied.
511
529
  func main() {
512
530
  inputPath := "delfour.data.json"
513
531
  jsonMode := false
@@ -1,5 +1,4 @@
1
1
  {
2
- "$schema": "./flandor.instance.schema.json",
3
2
  "caseName": "Flandor",
4
3
  "region": "Flanders",
5
4
  "question": "Is the Flemish Economic Resilience Board allowed to use a neutral macro-economic insight for regional stabilization, and if so which package should it activate for Flanders?",
@@ -1,5 +1,9 @@
1
1
  package main
2
2
 
3
+ // Flandor is a reference Arcling model for the regional retooling-pulse case.
4
+ // It evaluates whether a region needs intervention, selects the lowest-cost
5
+ // eligible package, and emits ARC text or a JSON report.
6
+
3
7
  import (
4
8
  "crypto/hmac"
5
9
  "crypto/sha256"
@@ -13,6 +17,7 @@ import (
13
17
  "time"
14
18
  )
15
19
 
20
+ // Data mirrors the input instance shape from flandor.data.json.
16
21
  type Data struct {
17
22
  CaseName string `json:"caseName"`
18
23
  Region string `json:"region"`
@@ -233,6 +238,8 @@ func parseTime(value string) time.Time {
233
238
  return t
234
239
  }
235
240
 
241
+ // stableStringify recursively sorts map keys so the canonical envelope is
242
+ // deterministic across runs and implementations.
236
243
  func stableStringify(value any) string {
237
244
  switch v := value.(type) {
238
245
  case nil:
@@ -260,6 +267,8 @@ func stableStringify(value any) string {
260
267
  }
261
268
  }
262
269
 
270
+ // canonicalValue converts typed structs into generic JSON-like values before
271
+ // stable stringification.
263
272
  func canonicalValue(value any) any {
264
273
  b, _ := json.Marshal(value)
265
274
  var out any
@@ -267,6 +276,7 @@ func canonicalValue(value any) any {
267
276
  return out
268
277
  }
269
278
 
279
+ // validateInstance performs the structural checks for the 4-file bundle.
270
280
  func validateInstance(data Data) error {
271
281
  if err := assertTrue(data.CaseName != "", "caseName is required"); err != nil {
272
282
  return err
@@ -283,6 +293,7 @@ func validateInstance(data Data) error {
283
293
  return nil
284
294
  }
285
295
 
296
+ // countTrue is used for the active-need threshold logic in the spec.
286
297
  func countTrue(values ...bool) int {
287
298
  total := 0
288
299
  for _, value := range values {
@@ -293,6 +304,7 @@ func countTrue(values ...bool) int {
293
304
  return total
294
305
  }
295
306
 
307
+ // The R* helpers map directly to named derivation clauses in flandor.spec.md.
296
308
  func clauseR1ExportWeakness(data Data) bool {
297
309
  for _, cluster := range data.Signals.Clusters {
298
310
  if cluster.ExportOrdersIndex < data.Thresholds.ExportOrdersIndexBelow {
@@ -318,6 +330,7 @@ func clauseR5NeedsRetoolingPulse(data Data, activeNeedCount int) bool {
318
330
  return activeNeedCount >= data.Thresholds.ActiveNeedCountAtLeast
319
331
  }
320
332
 
333
+ // deriveInsight produces the minimized regional signal shared with the recipient.
321
334
  func deriveInsight(data Data) Insight {
322
335
  return Insight{
323
336
  CreatedAt: data.Timestamps.CreatedAt,
@@ -333,6 +346,7 @@ func deriveInsight(data Data) Insight {
333
346
  }
334
347
  }
335
348
 
349
+ // derivePolicy constructs the usage restrictions paired with the insight.
336
350
  func derivePolicy(data Data) Policy {
337
351
  return Policy{
338
352
  Duty: Duty{
@@ -366,12 +380,16 @@ func derivePolicy(data Data) Policy {
366
380
  }
367
381
  }
368
382
 
383
+ // packageCoversAllActiveNeeds checks whether a candidate package addresses every
384
+ // need that is active for this specific instance.
369
385
  func packageCoversAllActiveNeeds(pkg Package, exportWeakness, skillsStrain, gridStress bool) bool {
370
386
  return (!exportWeakness || pkg.CoversExportWeakness) &&
371
387
  (!skillsStrain || pkg.CoversSkillsStrain) &&
372
388
  (!gridStress || pkg.CoversGridStress)
373
389
  }
374
390
 
391
+ // clauseS1EligiblePackages filters to packages that both fit the budget and
392
+ // cover the active needs.
375
393
  func clauseS1EligiblePackages(data Data, exportWeakness, skillsStrain, gridStress bool) []Package {
376
394
  eligible := make([]Package, 0)
377
395
  for _, pkg := range data.Packages {
@@ -383,6 +401,8 @@ func clauseS1EligiblePackages(data Data, exportWeakness, skillsStrain, gridStres
383
401
  return eligible
384
402
  }
385
403
 
404
+ // clauseS2RecommendedPackage applies the tie-breaker: choose the lowest-cost
405
+ // eligible package after sorting by cost.
386
406
  func clauseS2RecommendedPackage(data Data, exportWeakness, skillsStrain, gridStress bool) ([]Package, *Package) {
387
407
  eligible := clauseS1EligiblePackages(data, exportWeakness, skillsStrain, gridStress)
388
408
  if len(eligible) == 0 {
@@ -404,6 +424,8 @@ func clauseG3DutyTimely(data Data) bool {
404
424
  return !parseTime(data.Timestamps.DutyPerformedAt).After(parseTime(data.Timestamps.ExpiresAt))
405
425
  }
406
426
 
427
+ // clauseM1CanonicalEnvelope returns both the structured envelope and the
428
+ // deterministic string hashed/signed by the integrity clauses.
407
429
  func clauseM1CanonicalEnvelope(data Data) (Envelope, string) {
408
430
  envelope := Envelope{Insight: deriveInsight(data), Policy: derivePolicy(data)}
409
431
  return envelope, stableStringify(canonicalValue(envelope))
@@ -437,6 +459,8 @@ func yesNo(value bool) string {
437
459
  return "FAIL"
438
460
  }
439
461
 
462
+ // evaluate computes all derived facts, governance checks, integrity values,
463
+ // and presentation fields expected by flandor.expected.json.
440
464
  func evaluate(data Data) (Result, error) {
441
465
  if err := validateInstance(data); err != nil {
442
466
  return Result{}, err
@@ -593,6 +617,7 @@ func derefIntString(value *int) string {
593
617
  return fmt.Sprintf("%d", *value)
594
618
  }
595
619
 
620
+ // main is the CLI entry point used by the Arcling test runner.
596
621
  func main() {
597
622
  inputPath := "flandor.data.json"
598
623
  jsonMode := false
@@ -1,5 +1,4 @@
1
1
  {
2
- "$schema": "./medior.instance.schema.json",
3
2
  "caseName": "Medior",
4
3
  "region": "Flanders",
5
4
  "question": "Is the discharge coordination team allowed to use a minimal continuity insight after hospital discharge, and if so which package should it activate?",
@@ -1,5 +1,9 @@
1
1
  package main
2
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
+
3
7
  import (
4
8
  "crypto/hmac"
5
9
  "crypto/sha256"
@@ -13,6 +17,7 @@ import (
13
17
  "time"
14
18
  )
15
19
 
20
+ // Data mirrors the input instance shape from medior.data.json.
16
21
  type Data struct {
17
22
  CaseName string `json:"caseName"`
18
23
  Region string `json:"region"`
@@ -234,6 +239,8 @@ func parseTime(value string) time.Time {
234
239
  return t
235
240
  }
236
241
 
242
+ // stableStringify recursively sorts map keys so the canonical envelope stays
243
+ // byte-stable across runs and languages.
237
244
  func stableStringify(value any) string {
238
245
  switch v := value.(type) {
239
246
  case nil:
@@ -261,6 +268,8 @@ func stableStringify(value any) string {
261
268
  }
262
269
  }
263
270
 
271
+ // canonicalValue converts typed structs into generic JSON-like values before
272
+ // stable stringification.
264
273
  func canonicalValue(value any) any {
265
274
  b, _ := json.Marshal(value)
266
275
  var out any
@@ -268,6 +277,7 @@ func canonicalValue(value any) any {
268
277
  return out
269
278
  }
270
279
 
280
+ // validateInstance performs the structural checks for the 4-file bundle.
271
281
  func validateInstance(data Data) error {
272
282
  if err := assertTrue(data.CaseName != "", "caseName is required"); err != nil {
273
283
  return err
@@ -281,6 +291,7 @@ func validateInstance(data Data) error {
281
291
  return nil
282
292
  }
283
293
 
294
+ // countTrue is used for the active-need threshold logic in the spec.
284
295
  func countTrue(values ...bool) int {
285
296
  total := 0
286
297
  for _, value := range values {
@@ -291,6 +302,7 @@ func countTrue(values ...bool) int {
291
302
  return total
292
303
  }
293
304
 
305
+ // The R* helpers map directly to named derivation clauses in medior.spec.md.
294
306
  func clauseR1RenalSafetyConcern(data Data) bool {
295
307
  return data.Signals.Lab.Egfr < data.Thresholds.EgfrBelow
296
308
  }
@@ -315,6 +327,8 @@ func clauseR6NeedsContinuityBundle(data Data, activeNeedCount int) bool {
315
327
  return activeNeedCount >= data.Thresholds.ActiveNeedCountAtLeast
316
328
  }
317
329
 
330
+ // deriveInsight produces the minimized care-coordination signal shared with
331
+ // the recipient.
318
332
  func deriveInsight(data Data) Insight {
319
333
  return Insight{
320
334
  CreatedAt: data.Timestamps.CreatedAt,
@@ -330,6 +344,7 @@ func deriveInsight(data Data) Insight {
330
344
  }
331
345
  }
332
346
 
347
+ // derivePolicy constructs the usage restrictions paired with the insight.
333
348
  func derivePolicy(data Data) Policy {
334
349
  return Policy{
335
350
  Duty: Duty{
@@ -363,6 +378,8 @@ func derivePolicy(data Data) Policy {
363
378
  }
364
379
  }
365
380
 
381
+ // packageCoversAllActiveNeeds checks whether a candidate package addresses every
382
+ // active need in this instance.
366
383
  func packageCoversAllActiveNeeds(pkg Package, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow bool) bool {
367
384
  return (!renalSafetyConcern || pkg.CoversRenalSafetyConcern) &&
368
385
  (!polypharmacyRisk || pkg.CoversPolypharmacyRisk) &&
@@ -370,6 +387,8 @@ func packageCoversAllActiveNeeds(pkg Package, renalSafetyConcern, polypharmacyRi
370
387
  (!recentDischargeWindow || pkg.CoversRecentDischargeWindow)
371
388
  }
372
389
 
390
+ // clauseS1EligiblePackages filters to packages that both fit the budget and
391
+ // cover the active needs.
373
392
  func clauseS1EligiblePackages(data Data, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow bool) []Package {
374
393
  eligible := make([]Package, 0)
375
394
  for _, pkg := range data.Packages {
@@ -381,6 +400,8 @@ func clauseS1EligiblePackages(data Data, renalSafetyConcern, polypharmacyRisk, r
381
400
  return eligible
382
401
  }
383
402
 
403
+ // clauseS2RecommendedPackage applies the tie-breaker: choose the lowest-cost
404
+ // eligible package after sorting by cost.
384
405
  func clauseS2RecommendedPackage(data Data, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow bool) ([]Package, *Package) {
385
406
  eligible := clauseS1EligiblePackages(data, renalSafetyConcern, polypharmacyRisk, readmissionHistory, recentDischargeWindow)
386
407
  if len(eligible) == 0 {
@@ -402,6 +423,8 @@ func clauseG3DutyTimely(data Data) bool {
402
423
  return !parseTime(data.Timestamps.DutyPerformedAt).After(parseTime(data.Timestamps.ExpiresAt))
403
424
  }
404
425
 
426
+ // clauseM1CanonicalEnvelope returns both the structured envelope and the
427
+ // deterministic string hashed/signed by the integrity clauses.
405
428
  func clauseM1CanonicalEnvelope(data Data) (Envelope, string) {
406
429
  envelope := Envelope{Insight: deriveInsight(data), Policy: derivePolicy(data)}
407
430
  return envelope, stableStringify(canonicalValue(envelope))
@@ -435,6 +458,8 @@ func yesNo(value bool) string {
435
458
  return "FAIL"
436
459
  }
437
460
 
461
+ // evaluate computes all derived facts, governance checks, integrity values,
462
+ // and presentation fields expected by medior.expected.json.
438
463
  func evaluate(data Data) (Result, error) {
439
464
  if err := validateInstance(data); err != nil {
440
465
  return Result{}, err
@@ -589,6 +614,7 @@ func derefIntString(value *int) string {
589
614
  return fmt.Sprintf("%d", *value)
590
615
  }
591
616
 
617
+ // main is the CLI entry point used by the Arcling test runner.
592
618
  func main() {
593
619
  inputPath := "medior.data.json"
594
620
  jsonMode := false