eyeling 1.21.10 → 1.22.1

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.
package/HANDBOOK.md CHANGED
@@ -307,6 +307,31 @@ This avoids the “existential in the body” trap and matches how most rule aut
307
307
 
308
308
  Blanks in the **conclusion** are _not_ lifted — they remain blanks and later become existentials (Chapter 9).
309
309
 
310
+ ### 5.1.1 Quoted formulas keep their own blank-node scope
311
+
312
+ There is one important exception to the “lift blanks in rule bodies” rule: **do not descend into a quoted formula** (`GraphTerm`) and lift the blanks that appear _inside_ it.
313
+
314
+ So this rule body:
315
+
316
+ ```n3
317
+ {
318
+ ( { ?S a :Subject } { [] a :Thing } ) log:conjunction ?Z.
319
+ } => { ... }.
320
+ ```
321
+
322
+ must keep the inner `[]` as a **formula-local blank node**. Eyeling should treat it as belonging to the quoted graph, not as a rule-body variable that escapes into the surrounding rule.
323
+
324
+ That distinction matters because quoted formulas play **two different roles** in Eyeling:
325
+
326
+ 1. **Formula as data** — for example when constructing a formula with `log:conjunction` or storing `{ ... }` in a triple. In this role, local blanks stay blanks. They print as blank nodes and participate in alpha-equivalence only within that quoted formula.
327
+ 2. **Formula as a query pattern** — for example when `log:includes`, `log:notIncludes`, `log:collectAllIn`, or `log:forAllIn` prove a quoted formula. In that role, the builtin may treat the formula’s **local blanks existentially** while matching.
328
+
329
+ The practical rule is:
330
+
331
+ > **Rule normalization preserves blank-node scope inside quoted formulas; builtins may later interpret those preserved blanks as existential query placeholders when the formula is used as a pattern.**
332
+
333
+ This separation is deliberate. It keeps `log:conjunction` and formula printing honest, while still allowing query-like builtins to match formulas containing local `[]` placeholders.
334
+
310
335
  ### 5.2 Builtin deferral in forward-rule bodies
311
336
 
312
337
  In a depth-first proof, the order of goals matters. Many built-ins only become informative once parts of the triple are **already instantiated** (for example comparisons, pattern tests, and other built-ins that don’t normally create bindings).
@@ -1481,6 +1506,24 @@ Also supported:
1481
1506
 
1482
1507
  - The object may be the literal `true`, meaning the empty formula, which is always included (subject to the priority gating above).
1483
1508
 
1509
+ **Important blank-node note:** when the goal formula is used as a **pattern**, Eyeling treats blank nodes that are **local to that quoted formula** as existential placeholders during the proof.
1510
+
1511
+ So a pattern such as:
1512
+
1513
+ ```n3
1514
+ { ?x :p [] }
1515
+ ```
1516
+
1517
+ means “find an `?x` that has some `:p` value”, not “find the specific blank node label printed here”.
1518
+
1519
+ But that existential behavior is intentionally limited:
1520
+
1521
+ - it applies only to blanks that are **owned by the quoted formula being proved**
1522
+ - it does **not** rename or relax terms that were already supplied by an outer substitution
1523
+ - it does **not** turn concrete members of already-bound lists or other already-ground structures into fresh variables
1524
+
1525
+ That last point is easy to miss. A builtin may receive a formula after part of it has already been instantiated from outer bindings. Those substituted-in terms are fixed data, not fresh existential placeholders. Keeping that boundary sharp prevents accidental overmatching and keeps numeric/list-oriented examples stable.
1526
+
1484
1527
  #### `log:notIncludes` (test)
1485
1528
 
1486
1529
  Negation-as-failure version: it succeeds iff `log:includes` would yield no solutions (under the same scoping rules).
@@ -1494,6 +1537,8 @@ Negation-as-failure version: it succeeds iff `log:includes` would yield no solut
1494
1537
  - Unifies `OutList` with that list.
1495
1538
  - If `OutList` is a blank node, Eyeling just checks satisfiable without binding/collecting.
1496
1539
 
1540
+ As with `log:includes`, blank nodes that are local to `WhereFormula` behave as existential query placeholders while that formula is being proved. But blanks that came from already-bound outer data remain fixed.
1541
+
1497
1542
  This is essentially a list-producing “findall”.
1498
1543
 
1499
1544
  #### `log:forAllIn` (test)
@@ -6,7 +6,7 @@ An Arcling case sits alongside the declarative N3 cases in `examples/`. Its purp
6
6
 
7
7
  In one line:
8
8
 
9
- > `examples/arcling/` presents ARC cases in mathematical English with reference ECMAScript realizations and JSON test vectors.
9
+ > `examples/arcling/` presents ARC cases in mathematical English with reference Go realizations and JSON test vectors.
10
10
 
11
11
  ## Insight Economy context
12
12
 
@@ -27,7 +27,7 @@ Eyeling already has a strong way to present a case in declarative N3. Arcling ad
27
27
  Each Arcling case gives you:
28
28
 
29
29
  - a **normative statement** in mathematical English,
30
- - a **reference realization** in ECMAScript,
30
+ - a **reference realization** in Go,
31
31
  - a **concrete instance** in JSON,
32
32
  - and an **expected result** for comparison and regression testing.
33
33
 
@@ -65,7 +65,7 @@ Typical uses:
65
65
  - cases with a stable logical core and a small executable shell,
66
66
  - cases that benefit from conformance-style testing.
67
67
 
68
- ## The five files
68
+ ## The four files
69
69
 
70
70
  Each Arcling case should contain these files.
71
71
 
@@ -75,7 +75,7 @@ The normative case description.
75
75
 
76
76
  This file should use **mathematical English**. It should define the vocabulary, the inputs, the derived predicates, the decision rule, the governance rule, the checks, and the output contract.
77
77
 
78
- The spec should be written so that a careful reader can understand the case without reading the ECMAScript source first.
78
+ The spec should be written so that a careful reader can understand the case without reading the Go source first.
79
79
 
80
80
  ### 2. `name.data.json`
81
81
 
@@ -83,40 +83,36 @@ The concrete instance data.
83
83
 
84
84
  This file contains the facts for the case: entities, thresholds, observed values, policies, timestamps, candidate actions, and any other case inputs.
85
85
 
86
- ### 3. `name.model.mjs`
86
+ ### 3. `name.model.go`
87
87
 
88
- The reference ECMAScript realization.
88
+ The reference Go realization.
89
89
 
90
90
  This file should implement the case directly and clearly. A good pattern is to map named clauses in the spec to named functions in the model.
91
91
 
92
92
  For example:
93
93
 
94
- - `clauseR1_exportWeakness`
95
- - `clauseS2_recommendedPackage`
96
- - `clauseG1_authorizedUse`
97
- - `clauseM2_payloadHash`
94
+ - `clauseR1ExportWeakness`
95
+ - `clauseS2RecommendedPackage`
96
+ - `clauseG1AuthorizedUse`
97
+ - `clauseM2PayloadHash`
98
98
 
99
99
  The model is not the normative source. It is the **reference realization** of the normative source.
100
100
 
101
+ Input validation is part of the reference model. A malformed instance should fail before evaluation rather than requiring a separate schema artifact.
102
+
101
103
  ### 4. `name.expected.json`
102
104
 
103
105
  The expected derived result.
104
106
 
105
107
  This file is the conformance vector for the case. It should capture the main derived predicates, the selected answer, the visible checks, and any stable integrity values needed for regression testing.
106
108
 
107
- ### 5. `name.instance.schema.json`
108
-
109
- The instance schema.
110
-
111
- This file defines the required structure of the input JSON. It should be strict enough to catch malformed case instances before evaluation.
112
-
113
109
  ## How to read an Arcling case
114
110
 
115
111
  A good reading order is:
116
112
 
117
113
  1. start with `name.spec.md`,
118
114
  2. inspect `name.data.json`,
119
- 3. run `name.model.mjs`,
115
+ 3. run `go run name.model.go --json`,
120
116
  4. compare the result with `name.expected.json`,
121
117
  5. then relate the case back to its N3 counterpart.
122
118
 
@@ -127,7 +123,7 @@ That order keeps the meaning visible before the operational details.
127
123
  A useful mental model is:
128
124
 
129
125
  - `examples/` shows ARC cases in **declarative Eyeling form**,
130
- - `examples/arcling/` shows the same kind of cases in **mathematical-English specification plus reference ECMAScript form**.
126
+ - `examples/arcling/` shows the same kind of cases in **mathematical-English specification plus reference Go form**.
131
127
 
132
128
  So the two collections are complementary:
133
129
 
@@ -144,7 +140,7 @@ The spec should say what the case means. It should not merely paraphrase the cod
144
140
 
145
141
  ### 2. Keep the code direct
146
142
 
147
- The ECMAScript model should say what it does and do what it says. Avoid unnecessary framework machinery.
143
+ The Go model should say what it does and do what it says. Avoid unnecessary framework machinery.
148
144
 
149
145
  ### 3. Keep the data separate
150
146
 
@@ -163,7 +159,7 @@ If a case is called `delfour`, `medior`, or `flandor` in `examples/`, the Arclin
163
159
  1. Start from a strong ARC-style N3 example.
164
160
  2. Write a mathematical-English specification of the case.
165
161
  3. Move the concrete instance into JSON.
166
- 4. Implement a small ECMAScript reference model.
162
+ 4. Implement a small Go reference model.
167
163
  5. Capture the expected result in JSON.
168
164
  6. Keep the visible output in Answer / Reason Why / Check shape.
169
165
  7. Link the Arcling case to its N3 counterpart.
@@ -186,4 +182,4 @@ It exists to make a case simultaneously:
186
182
 
187
183
  ## In one line
188
184
 
189
- `examples/arcling/` presents ARC cases in mathematical English with reference ECMAScript realizations, JSON instances, and expected results, alongside declarative Eyeling examples.
185
+ `examples/arcling/` presents ARC cases in mathematical English with reference Go realizations, JSON instances, and expected results, alongside declarative Eyeling examples.
@@ -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?",