eyeling 1.22.6 → 1.22.7

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 (38) hide show
  1. package/HANDBOOK.md +245 -0
  2. package/dist/browser/eyeling.browser.js +128 -11
  3. package/examples/act-alarm-bit-interoperability.n3 +180 -0
  4. package/examples/act-barley-seed-lineage.n3 +565 -0
  5. package/examples/act-docking-abort.n3 +285 -0
  6. package/examples/act-gravity-mediator-witness.n3 +235 -0
  7. package/examples/act-isolation-breach.n3 +354 -0
  8. package/examples/act-photosynthetic-exciton-transfer.n3 +245 -0
  9. package/examples/act-sensor-memory-reset.n3 +190 -0
  10. package/examples/act-tunnel-junction-wake-switch.n3 +225 -0
  11. package/examples/act-yeast-self-reproduction.n3 +248 -0
  12. package/examples/complex-matrix-stability.n3 +288 -0
  13. package/examples/deck/act-barley-seed-lineage.md +593 -0
  14. package/examples/fundamental-theorem-arithmetic.n3 +244 -0
  15. package/examples/harborsmr.n3 +233 -0
  16. package/examples/meta-rule-audit.n3 +135 -0
  17. package/examples/output/act-alarm-bit-interoperability.txt +20 -0
  18. package/examples/output/act-barley-seed-lineage.txt +25 -0
  19. package/examples/output/act-docking-abort.txt +22 -0
  20. package/examples/output/act-gravity-mediator-witness.txt +24 -0
  21. package/examples/output/act-isolation-breach.txt +27 -0
  22. package/examples/output/act-photosynthetic-exciton-transfer.txt +20 -0
  23. package/examples/output/act-sensor-memory-reset.txt +20 -0
  24. package/examples/output/act-tunnel-junction-wake-switch.txt +21 -0
  25. package/examples/output/act-yeast-self-reproduction.txt +23 -0
  26. package/examples/output/complex-matrix-stability.txt +14 -0
  27. package/examples/output/fundamental-theorem-arithmetic.txt +15 -0
  28. package/examples/output/get-uuid.n3 +2 -2
  29. package/examples/output/harborsmr.txt +20 -0
  30. package/examples/output/meta-rule-audit.n3 +44 -0
  31. package/examples/output/theory-diff.n3 +22 -0
  32. package/examples/theory-diff.n3 +125 -0
  33. package/eyeling.js +128 -11
  34. package/lib/builtins.js +18 -1
  35. package/lib/cli.js +31 -5
  36. package/lib/engine.js +79 -5
  37. package/package.json +1 -1
  38. package/test/api.test.js +69 -0
@@ -0,0 +1,24 @@
1
+ ACT gravity mediator witness
2
+
3
+ Answer
4
+ YES for the mediator-only witness run.
5
+ NO for a purely classical mediator model under the same mediator-only conditions.
6
+
7
+ Reason Why
8
+ The positive run assumes locality and interoperability, excludes direct coupling between the two quantum systems, and records an entanglement witness after interaction through the mediator alone. Under those constructor-theoretic conditions, the mediator must be non-classical, so the run rules out a purely classical mediator model. The contrast run keeps the same locality, interoperability, and mediator-only structure but assigns the mediator a purely classical model. In that case the mediator-only entanglement witness is blocked, so the run cannot support the same non-classicality conclusion.
9
+
10
+ Check
11
+ C1 OK - locality is assumed in the positive run
12
+ C2 OK - interoperability is assumed in the positive run
13
+ C3 OK - direct coupling between the two quantum systems is excluded
14
+ C4 OK - the positive run has a mediator-only interaction path
15
+ C5 OK - an entanglement witness is observed in the positive run
16
+ C6 OK - the positive run supports an information-transfer interface
17
+ C7 OK - the positive run supports local readout
18
+ C8 OK - the positive mediator is derived to be non-classical
19
+ C9 OK - a purely classical mediator model is ruled out by the positive run
20
+ C10 OK - the non-classicality conclusion applies to the gravitational mediator
21
+ C11 OK - the contrast run is also mediator-only
22
+ C12 OK - the contrast run cannot support a mediator-only entanglement witness
23
+ C13 OK - the purely classical gravitational mediator cannot mediate entanglement under the witness conditions
24
+ C14 OK - the contrast run cannot support the non-classicality conclusion
@@ -0,0 +1,27 @@
1
+ ACT isolation-breach token — broad constructor-theory coverage case
2
+
3
+ Answer
4
+ YES for the classical isolation-breach token.
5
+ NO for universal cloning and unrestricted fan-out of the quantum provenance seal.
6
+
7
+ Reason Why
8
+ The isolation-breach token is treated as an abstract information variable carried by unlike classical media: a door beacon, a containment PLC, a nurse pager, and an incident board. Because those substrates are information media for the same variable, the token can be prepared, permuted, reversed, cloned locally, copied across media, measured into an output record, and composed into serial and parallel task networks. By contrast, the specimen seal is treated as a superinformation medium, so cloning all of its states is impossible and unrestricted parallel fan-out is blocked.
9
+
10
+ Check
11
+ C1 OK - the door beacon is an information medium
12
+ C2 OK - the containment PLC is an information medium
13
+ C3 OK - the nurse pager is an information medium
14
+ C4 OK - the incident board is an information medium
15
+ C5 OK - the door beacon distinguishes the breach bit
16
+ C6 OK - the breach state can be prepared on the nurse pager
17
+ C7 OK - permutation from safe to breach is possible on the door beacon
18
+ C8 OK - the door beacon supports reversible permutation
19
+ C9 OK - local cloning of the breach bit is possible on the containment PLC
20
+ C10 OK - the breach bit can be copied from door beacon to containment PLC
21
+ C11 OK - the breach bit can be copied from containment PLC to nurse pager
22
+ C12 OK - the breach bit can be measured from nurse pager into the incident board
23
+ C13 OK - a serial network from door beacon via containment PLC to incident board is possible
24
+ C14 OK - a parallel network from containment PLC to nurse pager and incident board is possible
25
+ C15 OK - cloning all states of the specimen seal is an impossible task
26
+ C16 OK - the specimen seal cannot be universally cloned
27
+ C17 OK - the specimen seal cannot support unrestricted parallel fan-out
@@ -0,0 +1,20 @@
1
+ ACT photosynthetic exciton transfer
2
+
3
+ Answer
4
+ YES for the tuned antenna complex.
5
+ NO for the detuned, strongly decohered contrast complex.
6
+
7
+ Reason Why
8
+ The tuned complex can sample exciton pathways coherently, use vibronically assisted transfer, and exploit short-lived quantum assistance along a downhill route to the reaction center. That makes efficient exciton transfer and reaction-center delivery possible in this case. The detuned contrast complex lacks the same alignment: coherent pathway sampling is blocked, vibronic assistance is unavailable, and the energy landscape is mismatched, so efficient reaction-center delivery is not possible in the same operating picture.
9
+
10
+ Check
11
+ C1 OK - the tuned complex can sample exciton pathways coherently
12
+ C2 OK - the tuned complex can use vibronically assisted transfer
13
+ C3 OK - short-lived quantum assistance is enough in the tuned downhill regime
14
+ C4 OK - efficient exciton transfer is possible in the tuned complex
15
+ C5 OK - the tuned complex can deliver excitation to the reaction center
16
+ C6 OK - the detuned complex cannot sample pathways coherently
17
+ C7 OK - the detuned complex cannot use vibronically assisted transfer
18
+ C8 OK - the detuned complex cannot achieve directed reaction-center transfer
19
+ C9 OK - the detuned complex cannot achieve efficient exciton transfer
20
+ C10 OK - the detuned complex cannot deliver excitation efficiently to the reaction center
@@ -0,0 +1,20 @@
1
+ ACT sensor memory reset
2
+
3
+ Answer
4
+ YES with the battery pack.
5
+ NO with the ambient heat bath alone.
6
+
7
+ Reason Why
8
+ The alarm latch is a one-bit memory that must be reset to its standard clear state before the radiation sensor can be reused. In this case, the charged battery pack is treated as a work medium, so it can drive a controlled reset and prepare the latch in its reusable standard state. The ambient bath is treated as a heat medium, so by itself it cannot perform the same reliable directed reset. The example also shows an irreversibility pattern: useful work can be degraded into dissipated heat during reset, but the ambient heat bath alone cannot reconstruct the charged work resource.
9
+
10
+ Check
11
+ C1 OK - the battery pack can drive a controlled reset
12
+ C2 OK - the alarm latch can be reliably reset from work
13
+ C3 OK - the latch can be prepared in its standard reusable state
14
+ C4 OK - the sensor can be made ready for reuse
15
+ C5 OK - the work resource can degrade to heat during reset
16
+ C6 OK - the ambient heat bath cannot drive a controlled reset
17
+ C7 OK - the latch cannot be reliably reset from heat alone
18
+ C8 OK - the latch cannot be prepared in its standard state from heat alone
19
+ C9 OK - the sensor cannot be made ready for reuse from heat alone
20
+ C10 OK - the ambient heat bath cannot reconstruct the charged work resource by itself
@@ -0,0 +1,21 @@
1
+ ACT tunnel-junction wake switch
2
+
3
+ Answer
4
+ YES for the tunnel junction.
5
+ NO for the conventional low-bias PN junction in the same wake-switch regime.
6
+
7
+ Reason Why
8
+ The tunnel junction is modeled as a heavily doped narrow PN junction with overlapping states, so quantum barrier transfer is possible. That makes sub-threshold current possible in the low-forward-bias regime, which in turn makes ultra-low-bias switching possible for the wake circuit. Because the device is also scanned through a peak-to-valley window, a negative differential response is possible as well. By contrast, the conventional junction lacks the structural conditions for the same transfer mode, so it cannot deliver the same low-bias switching task in this case.
9
+
10
+ Check
11
+ C1 OK - the tunnel junction can support quantum barrier transfer
12
+ C2 OK - the tunnel junction is classified as tunneling-dominant
13
+ C3 OK - the tunnel junction can deliver sub-threshold current
14
+ C4 OK - the tunnel junction can show negative differential response
15
+ C5 OK - the tunnel junction can perform ultra-low-bias switching
16
+ C6 OK - the tunnel junction can serve the leak-alarm wake circuit
17
+ C7 OK - the conventional junction cannot support the same quantum barrier transfer
18
+ C8 OK - the conventional junction cannot deliver sub-threshold current in this regime
19
+ C9 OK - the conventional junction cannot show the tunnel-style negative differential response
20
+ C10 OK - the conventional junction cannot perform ultra-low-bias switching here
21
+ C11 OK - the conventional junction cannot serve the leak-alarm wake circuit in this case
@@ -0,0 +1,23 @@
1
+ ACT yeast self-reproduction
2
+
3
+ Answer
4
+ YES for the viable starter culture.
5
+ NO for accurate self-reproduction in the non-digital contrast lineage.
6
+
7
+ Reason Why
8
+ The starter genome is treated as a replicator storing digital hereditary information, while the cell machinery is treated as the vehicle that enables metabolism and copying support. Under no-design laws, digital information makes accurate genome copying possible. Because the replicator is accurate and paired with a vehicle, the whole starter cell qualifies as a self-reproducer. With a variation source and a selection environment, natural selection also becomes possible. By contrast, the non-digital lineage cannot support accurate genome copying under the same no-design-laws assumption, so it cannot sustain the same accurate self-reproduction or natural-selection story.
9
+
10
+ Check
11
+ C1 OK - no-design laws are assumed
12
+ C2 OK - digital information is physically instantiated for the viable lineage
13
+ C3 OK - a viable replicator is present
14
+ C4 OK - a viable vehicle is present
15
+ C5 OK - accurate genome copying is possible for the viable lineage
16
+ C6 OK - the viable lineage has a replicator-plus-vehicle architecture
17
+ C7 OK - the starter cell qualifies as a self-reproducer
18
+ C8 OK - heritable variation is possible for the viable lineage
19
+ C9 OK - the viable starter culture can support a natural-selection lineage
20
+ C10 OK - the fitter viable variant is selected in the fermenter
21
+ C11 OK - the non-digital contrast genome cannot be copied accurately under no-design laws
22
+ C12 OK - the non-digital contrast cell cannot achieve accurate self-reproduction
23
+ C13 OK - the non-digital contrast cell cannot support the same natural-selection lineage
@@ -0,0 +1,14 @@
1
+ Complex Matrix Stability — ARC-style
2
+
3
+ Answer
4
+ We compare three diagonal 2x2 complex matrices for discrete-time stability: A_unstable = [[(1,1),(0,0)],[(0,0),(2,0)]], A_stable = [[(1,0),(0,0)],[(0,0),(-1,0)]], and A_damped = [[(0,0),(0,0)],[(0,0),(0,0)]]. Their spectral radii are ρ(A_unstable) = 2, ρ(A_stable) = 1, and ρ(A_damped) = 0. So A_unstable is unstable, A_stable is marginally stable, and A_damped is damped.
5
+
6
+ Reason Why
7
+ For a discrete-time linear system x_{k+1} = A x_k, the eigenvalues of A govern the behaviour of the modes. Because these matrices are diagonal, the eigenvalues are just the diagonal entries. The spectral radius is the maximum modulus of the eigenvalues: if it is greater than 1 a mode grows, if it equals 1 the modes remain bounded without decaying, and if it is less than 1 all modes decay to zero. Here the diagonal entries give radii 2, 1, and 0 respectively, which explains the three classifications.
8
+
9
+ Check
10
+ C1 OK - A_unstable has eigenvalues (1,1) and (2,0) with spectral radius 2, so it is unstable.
11
+ C2 OK - A_stable has eigenvalues (1,0) and (-1,0) with spectral radius 1, so it is marginally stable.
12
+ C3 OK - A_damped has eigenvalues (0,0) and (0,0) with spectral radius 0, so every mode decays to zero.
13
+ C4 OK - for z = (1,2) and w = (0,1), the squared modulus of z*w equals the product of the squared moduli.
14
+ C5 OK - the spectral-radius-squared of 2*A_unstable is four times that of A_unstable.
@@ -0,0 +1,15 @@
1
+ Fundamental Theorem of Arithmetic — ARC-style
2
+
3
+ Answer
4
+ For n = 202692987, the prime factors are 3 * 3 * 7 * 829 * 3881, the prime-power form is 3^2 * 7 * 829 * 3881, and the product of these factors is 202692987 with 4 distinct primes.
5
+
6
+ Reason Why
7
+ Existence in this run comes from repeated smallest-divisor decomposition: 202692987 factors as 3 * 3 * 7 * 829 * 3881. Each distinct factor is prime. For uniqueness up to order, the reverse traversal gives 3881 * 829 * 7 * 3 * 3, and both traversals sort to the same multiset of primes. So this concrete case exhibits the Fundamental Theorem of Arithmetic for 202692987: a prime factorization exists and is unique up to order. The extreme prime factors are 3 and 3881.
8
+
9
+ Check
10
+ C1 OK - repeated smallest-divisor decomposition produced the expected smallest-first factor list (3 3 7 829 3881).
11
+ C2 OK - the product of the computed factors reconstructs n = 202692987.
12
+ C3 OK - every distinct factor in the decomposition is prime by trial division.
13
+ C4 OK - the prime-power form matches 3^2 * 7 * 829 * 3881.
14
+ C5 OK - smallest-first and largest-first traversals have the same multiset of primes, so the factorization agrees up to order.
15
+ C6 OK - the smallest and largest prime factors are 3 and 3881.
@@ -1,2 +1,2 @@
1
- <urn:uuid:ad88d7b6-5b37-4eeb-a044-7bca1ffc366c> <a> <b> .
2
- <urn:uuid:37d41865-0910-9953-46c7-01359fbab6fa> <a> <b> .
1
+ <urn:uuid:e6a48091-90e6-72fc-d944-9891bcca2363> <file:///home/jdroo/github.com/eyereasoner/eyeling/examples/a> <file:///home/jdroo/github.com/eyereasoner/eyeling/examples/b> .
2
+ <urn:uuid:8228641a-8d20-b064-4ae2-12e31442492a> <file:///home/jdroo/github.com/eyereasoner/eyeling/examples/a> <file:///home/jdroo/github.com/eyereasoner/eyeling/examples/b> .
@@ -0,0 +1,20 @@
1
+ HarborSMR — bounded flexible-export insight for port electrolysis
2
+
3
+ Answer
4
+ PERMIT
5
+ The port hydrogen hub may use the SMR insight to run PEM electrolyzer train 2 at 16 MW from 14:00 to 18:00.
6
+
7
+ Reason Why
8
+ The operator shares only a narrow, expiring insight that a temporary 18 MW flexible-export window is available. The request is for electrolysis dispatch only, the requested 16 MW fits inside the permitted window, safety margins are above threshold, no outage blocks the window, and the policy forbids redistribution for market resale. Raw reactor telemetry stays local.
9
+
10
+ Check
11
+ C1 OK - reserve margin exceeds the dispatch threshold
12
+ C2 OK - cooling margin exceeds the dispatch threshold
13
+ C3 OK - no planned outage blocks the window
14
+ C4 OK - requested MW fits within the export window
15
+ C5 OK - serialized insight omits sensitive telemetry terms
16
+ C6 OK - aggregate excludes core temperature, rod position, neutron flux, and operator IDs
17
+ C7 OK - policy allows use for electrolysis dispatch before expiry
18
+ C8 OK - policy prohibits redistribution for market resale
19
+ C9 OK - scope is explicit: device, event, start, and expiry
20
+ C10 OK - dispatch plan matches the requested load and power
@@ -0,0 +1,44 @@
1
+ @prefix : <http://example.org/> .
2
+ @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
3
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
4
+
5
+ {
6
+ ?X a ?C .
7
+ ?C rdfs:subClassOf ?D .
8
+ } :ruleStatus :Bidirectional .
9
+ {
10
+ ?X a ?C .
11
+ ?C rdfs:subClassOf ?D .
12
+ } :ruleHead {
13
+ ?X a ?D .
14
+ } .
15
+ {
16
+ ?P :parentOf ?Q .
17
+ } :ruleStatus :ForwardOnly .
18
+ {
19
+ ?P :parentOf ?Q .
20
+ } :ruleHead {
21
+ ?Q :childOf ?P .
22
+ } .
23
+ {
24
+ ?Org :employs ?P .
25
+ } :ruleStatus :BackwardOnly .
26
+ {
27
+ ?Org :employs ?P .
28
+ } :ruleHead {
29
+ ?P :worksFor ?Org .
30
+ } .
31
+ {
32
+ :alice a :Student .
33
+ :Student rdfs:subClassOf :Person .
34
+ } :activeAs :ForwardBody .
35
+ {
36
+ :alice :parentOf :bob .
37
+ } :activeAs :ForwardBody .
38
+ {
39
+ :alice a :Student .
40
+ :Student rdfs:subClassOf :Person .
41
+ } :activeAs :BackwardBody .
42
+ {
43
+ :acme :employs :carol .
44
+ } :activeAs :BackwardBody .
@@ -0,0 +1,22 @@
1
+ @prefix : <http://example.org/> .
2
+
3
+ {
4
+ ?P :parentOf ?Q .
5
+ } :missingForwardRule {
6
+ ?Q :childOf ?P .
7
+ } .
8
+ {
9
+ ?Org :employs ?P .
10
+ } :missingBackwardRule {
11
+ ?P :worksFor ?Org .
12
+ } .
13
+ {
14
+ ?Org :employs ?P .
15
+ } :extraForwardRule {
16
+ ?P :worksFor ?Org .
17
+ } .
18
+ {
19
+ ?P :mentors ?Q .
20
+ } :extraForwardRule {
21
+ ?Q :menteeOf ?P .
22
+ } .
@@ -0,0 +1,125 @@
1
+ # =======================================================
2
+ # Theory diff for quoted rule sets
3
+ #
4
+ # Compares two quoted theories and reports:
5
+ # - forward rules missing from the candidate
6
+ # - backward rules missing from the candidate
7
+ # - extra forward rules in the candidate
8
+ # - extra backward rules in the candidate
9
+ #
10
+ # It exercises:
11
+ # - multiple quoted formulas as first-class values
12
+ # - log:includes on quoted => and <=
13
+ # - log:notIncludes for structural diffing
14
+ # - matching quoted rule bodies and heads across formulas
15
+ # =======================================================
16
+
17
+ @prefix : <http://example.org/> .
18
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
19
+ @prefix log: <http://www.w3.org/2000/10/swap/log#> .
20
+
21
+ <> :base {
22
+ {
23
+ ?X a ?C .
24
+ ?C rdfs:subClassOf ?D .
25
+ }
26
+ =>
27
+ {
28
+ ?X a ?D .
29
+ }.
30
+
31
+ {
32
+ ?P :parentOf ?Q .
33
+ }
34
+ =>
35
+ {
36
+ ?Q :childOf ?P .
37
+ }.
38
+
39
+ {
40
+ ?P :worksFor ?Org .
41
+ }
42
+ <=
43
+ {
44
+ ?Org :employs ?P .
45
+ }.
46
+ }.
47
+
48
+ <> :candidate {
49
+ {
50
+ ?X a ?C .
51
+ ?C rdfs:subClassOf ?D .
52
+ }
53
+ =>
54
+ {
55
+ ?X a ?D .
56
+ }.
57
+
58
+ {
59
+ ?Org :employs ?P .
60
+ }
61
+ =>
62
+ {
63
+ ?P :worksFor ?Org .
64
+ }.
65
+
66
+ {
67
+ ?P :mentors ?Q .
68
+ }
69
+ =>
70
+ {
71
+ ?Q :menteeOf ?P .
72
+ }.
73
+ }.
74
+
75
+ # --------------------
76
+ # Missing in candidate
77
+ # --------------------
78
+
79
+ {
80
+ ?W :base ?Base.
81
+ ?W :candidate ?Cand.
82
+ ?Base log:includes { ?B log:implies ?H }.
83
+ ?Cand log:notIncludes { ?B log:implies ?H }.
84
+ }
85
+ =>
86
+ {
87
+ ?B :missingForwardRule ?H .
88
+ }.
89
+
90
+ {
91
+ ?W :base ?Base.
92
+ ?W :candidate ?Cand.
93
+ ?Base log:includes { ?H log:impliedBy ?B }.
94
+ ?Cand log:notIncludes { ?H log:impliedBy ?B }.
95
+ }
96
+ =>
97
+ {
98
+ ?B :missingBackwardRule ?H .
99
+ }.
100
+
101
+ # ------------------
102
+ # Extra in candidate
103
+ # ------------------
104
+
105
+ {
106
+ ?W :base ?Base.
107
+ ?W :candidate ?Cand.
108
+ ?Cand log:includes { ?B log:implies ?H }.
109
+ ?Base log:notIncludes { ?B log:implies ?H }.
110
+ }
111
+ =>
112
+ {
113
+ ?B :extraForwardRule ?H .
114
+ }.
115
+
116
+ {
117
+ ?W :base ?Base.
118
+ ?W :candidate ?Cand.
119
+ ?Cand log:includes { ?H log:impliedBy ?B }.
120
+ ?Base log:notIncludes { ?H log:impliedBy ?B }.
121
+ }
122
+ =>
123
+ {
124
+ ?B :extraBackwardRule ?H .
125
+ }.
package/eyeling.js CHANGED
@@ -2354,6 +2354,23 @@ function __logNaturalPriorityFromTerm(t) {
2354
2354
  // ===========================================================================
2355
2355
  // Backward proof & builtins mutual recursion — declarations first
2356
2356
 
2357
+ function __varCameFromBoundSubstitution(goalTerm, subst) {
2358
+ if (!(goalTerm instanceof Var)) return false;
2359
+ if (!subst || !Object.prototype.hasOwnProperty.call(subst, goalTerm.name)) return false;
2360
+
2361
+ let cur = subst[goalTerm.name];
2362
+ const seen = new Set([goalTerm.name]);
2363
+
2364
+ while (cur instanceof Var) {
2365
+ if (seen.has(cur.name)) return true;
2366
+ seen.add(cur.name);
2367
+ if (!Object.prototype.hasOwnProperty.call(subst, cur.name)) return true;
2368
+ cur = subst[cur.name];
2369
+ }
2370
+
2371
+ return false;
2372
+ }
2373
+
2357
2374
  function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2358
2375
  const g = applySubstTriple(goal, subst);
2359
2376
  const pv = iriValue(g.p);
@@ -3820,7 +3837,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3820
3837
  // Schema: $s+ log:rawType $o-
3821
3838
  // Returns one of log:Formula, log:Literal, rdf:List, or log:Other.
3822
3839
  if (pv === LOG_NS + 'rawType') {
3823
- if (g.s instanceof Var) return [];
3840
+ if (g.s instanceof Var && !__varCameFromBoundSubstitution(goal.s, subst)) return [];
3824
3841
 
3825
3842
  let ty;
3826
3843
  if (g.s instanceof GraphTerm) ty = internIri(LOG_NS + 'Formula');
@@ -4870,7 +4887,11 @@ module.exports = {
4870
4887
 
4871
4888
  'use strict';
4872
4889
 
4890
+ const path = require('node:path');
4891
+ const { pathToFileURL } = require('node:url');
4892
+
4873
4893
  const engine = require('./engine');
4894
+ const deref = require('./deref');
4874
4895
  const { PrefixEnv } = require('./prelude');
4875
4896
 
4876
4897
  function offsetToLineCol(text, offset) {
@@ -4913,6 +4934,29 @@ function readTextFromStdinSync() {
4913
4934
  return fs.readFileSync(0, { encoding: 'utf8' });
4914
4935
  }
4915
4936
 
4937
+ function __isNetworkOrFileIri(s) {
4938
+ return typeof s === 'string' && /^(https?:|file:\/\/)/i.test(s);
4939
+ }
4940
+
4941
+ function __sourceLabelToBaseIri(sourceLabel) {
4942
+ if (!sourceLabel || sourceLabel === '<stdin>') return '';
4943
+ if (__isNetworkOrFileIri(sourceLabel)) return deref.stripFragment(sourceLabel);
4944
+ return pathToFileURL(path.resolve(sourceLabel)).toString();
4945
+ }
4946
+
4947
+ function __readInputSourceSync(sourceLabel) {
4948
+ if (sourceLabel === '<stdin>') return readTextFromStdinSync();
4949
+
4950
+ if (__isNetworkOrFileIri(sourceLabel)) {
4951
+ const txt = deref.derefTextSync(sourceLabel);
4952
+ if (typeof txt !== 'string') throw new Error(`Failed to dereference ${sourceLabel}`);
4953
+ return txt;
4954
+ }
4955
+
4956
+ const fs = require('node:fs');
4957
+ return fs.readFileSync(sourceLabel, { encoding: 'utf8' });
4958
+ }
4959
+
4916
4960
  function main() {
4917
4961
  // Drop "node" and script name; keep only user-provided args
4918
4962
  // Expand combined short options: -pt == -p -t
@@ -5026,13 +5070,11 @@ function main() {
5026
5070
  }
5027
5071
 
5028
5072
  const sourceLabel = useImplicitStdin || positional[0] === '-' ? '<stdin>' : positional[0];
5073
+ const baseIri = __sourceLabelToBaseIri(sourceLabel);
5074
+
5029
5075
  let text;
5030
5076
  try {
5031
- if (sourceLabel === '<stdin>') text = readTextFromStdinSync();
5032
- else {
5033
- const fs = require('node:fs');
5034
- text = fs.readFileSync(sourceLabel, { encoding: 'utf8' });
5035
- }
5077
+ text = __readInputSourceSync(sourceLabel);
5036
5078
  } catch (e) {
5037
5079
  if (sourceLabel === '<stdin>') console.error(`Error reading stdin: ${e.message}`);
5038
5080
  else console.error(`Error reading file ${JSON.stringify(sourceLabel)}: ${e.message}`);
@@ -5044,6 +5086,7 @@ function main() {
5044
5086
  try {
5045
5087
  toks = engine.lex(text);
5046
5088
  const parser = new engine.Parser(toks);
5089
+ if (baseIri) parser.prefixes.setBase(baseIri);
5047
5090
  [prefixes, triples, frules, brules, qrules] = parser.parseDocument();
5048
5091
  // Make the parsed prefixes available to log:trace output (CLI path)
5049
5092
  engine.setTracePrefixes(prefixes);
@@ -5951,21 +5994,80 @@ function __isStrictGroundTriple(tr) {
5951
5994
  // -----------------------------------------------------------------------------
5952
5995
  // Used to maintain O(1) membership sets for dynamically promoted rules, and to
5953
5996
  // memoize per-firing head-blank skolemization.
5997
+ //
5998
+ // Important: variables and blank nodes *inside quoted formulas* are local to the
5999
+ // formula. Canonicalize those labels by first occurrence so alpha-equivalent
6000
+ // formulas (for example the repeated results of log:semantics after
6001
+ // standardize-apart) get the same identity key. Keep top-level blank labels
6002
+ // untouched so distinct existential witnesses in the global fact set do not
6003
+ // collapse together.
6004
+ function __keyFromTermForRuleIdentity(term) {
6005
+ const ctx = { quotedVar: new Map(), quotedBlank: new Map() };
6006
+
6007
+ function canonQuotedVar(name) {
6008
+ let out = ctx.quotedVar.get(name);
6009
+ if (!out) {
6010
+ out = `v${ctx.quotedVar.size}`;
6011
+ ctx.quotedVar.set(name, out);
6012
+ }
6013
+ return out;
6014
+ }
6015
+
6016
+ function canonQuotedBlank(label) {
6017
+ let out = ctx.quotedBlank.get(label);
6018
+ if (!out) {
6019
+ out = `b${ctx.quotedBlank.size}`;
6020
+ ctx.quotedBlank.set(label, out);
6021
+ }
6022
+ return out;
6023
+ }
6024
+
6025
+ function enc(u, inQuotedFormula) {
6026
+ if (u instanceof Iri) return ['I', u.value];
6027
+ if (u instanceof Literal) return ['L', u.value];
6028
+ if (u instanceof Blank) return inQuotedFormula ? ['BQ', canonQuotedBlank(u.label)] : ['B', u.label];
6029
+ if (u instanceof Var) return inQuotedFormula ? ['VQ', canonQuotedVar(u.name)] : ['V', u.name];
6030
+ if (u instanceof ListTerm) return ['List', u.elems.map((e) => enc(e, inQuotedFormula))];
6031
+ if (u instanceof OpenListTerm) {
6032
+ return [
6033
+ 'OpenList',
6034
+ u.prefix.map((e) => enc(e, inQuotedFormula)),
6035
+ inQuotedFormula ? ['TailVQ', canonQuotedVar(u.tailVar)] : ['TailV', u.tailVar],
6036
+ ];
6037
+ }
6038
+ if (u instanceof GraphTerm)
6039
+ return ['Graph', u.triples.map((tr) => [enc(tr.s, true), enc(tr.p, true), enc(tr.o, true)])];
6040
+ return ['Other', String(u)];
6041
+ }
6042
+
6043
+ return JSON.stringify(enc(term, false));
6044
+ }
6045
+
5954
6046
  function __ruleKey(isForward, isFuse, premise, conclusion, dynamicConclusionTerm /* optional */) {
5955
6047
  let out = (isForward ? 'F' : 'B') + (isFuse ? '!' : '') + '|P|';
5956
6048
  for (let i = 0; i < premise.length; i++) {
5957
6049
  const tr = premise[i];
5958
6050
  if (i) out += '\n';
5959
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
6051
+ out +=
6052
+ __keyFromTermForRuleIdentity(tr.s) +
6053
+ '\t' +
6054
+ __keyFromTermForRuleIdentity(tr.p) +
6055
+ '\t' +
6056
+ __keyFromTermForRuleIdentity(tr.o);
5960
6057
  }
5961
6058
  out += '|C|';
5962
6059
  for (let i = 0; i < conclusion.length; i++) {
5963
6060
  const tr = conclusion[i];
5964
6061
  if (i) out += '\n';
5965
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
6062
+ out +=
6063
+ __keyFromTermForRuleIdentity(tr.s) +
6064
+ '\t' +
6065
+ __keyFromTermForRuleIdentity(tr.p) +
6066
+ '\t' +
6067
+ __keyFromTermForRuleIdentity(tr.o);
5966
6068
  }
5967
6069
  if (dynamicConclusionTerm) {
5968
- out += '|T|' + skolemKeyFromTerm(dynamicConclusionTerm);
6070
+ out += '|T|' + __keyFromTermForRuleIdentity(dynamicConclusionTerm);
5969
6071
  }
5970
6072
  return out;
5971
6073
  }
@@ -5976,7 +6078,12 @@ function __firingKey(ruleIndex, instantiatedPremises) {
5976
6078
  for (let i = 0; i < instantiatedPremises.length; i++) {
5977
6079
  const tr = instantiatedPremises[i];
5978
6080
  if (i) out += '\n';
5979
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
6081
+ out +=
6082
+ __keyFromTermForRuleIdentity(tr.s) +
6083
+ '\t' +
6084
+ __keyFromTermForRuleIdentity(tr.p) +
6085
+ '\t' +
6086
+ __keyFromTermForRuleIdentity(tr.o);
5980
6087
  }
5981
6088
  return out;
5982
6089
  }
@@ -8216,7 +8323,17 @@ function proveGoals(goals, subst, facts, backRules, depth, visited, varGen, maxR
8216
8323
  if (remaining <= 0) continue;
8217
8324
  const builtinMax = Number.isFinite(remaining) && !restGoals.length ? remaining : undefined;
8218
8325
 
8219
- let deltas = evalBuiltin(goal0, {}, facts, backRules, frame.curDepth, varGen, builtinMax);
8326
+ const builtinGoalForEval = goalPredicateIri === LOG_NS + 'rawType' ? rawGoal : goal0;
8327
+ const builtinSubstForEval = goalPredicateIri === LOG_NS + 'rawType' ? substMut : {};
8328
+ let deltas = evalBuiltin(
8329
+ builtinGoalForEval,
8330
+ builtinSubstForEval,
8331
+ facts,
8332
+ backRules,
8333
+ frame.curDepth,
8334
+ varGen,
8335
+ builtinMax,
8336
+ );
8220
8337
 
8221
8338
  const dc = typeof frame.deferCount === 'number' ? frame.deferCount : 0;
8222
8339
  const builtinDeltasAreVacuous = deltas.length > 0 && deltas.every((d) => Object.keys(d).length === 0);
package/lib/builtins.js CHANGED
@@ -1875,6 +1875,23 @@ function __logNaturalPriorityFromTerm(t) {
1875
1875
  // ===========================================================================
1876
1876
  // Backward proof & builtins mutual recursion — declarations first
1877
1877
 
1878
+ function __varCameFromBoundSubstitution(goalTerm, subst) {
1879
+ if (!(goalTerm instanceof Var)) return false;
1880
+ if (!subst || !Object.prototype.hasOwnProperty.call(subst, goalTerm.name)) return false;
1881
+
1882
+ let cur = subst[goalTerm.name];
1883
+ const seen = new Set([goalTerm.name]);
1884
+
1885
+ while (cur instanceof Var) {
1886
+ if (seen.has(cur.name)) return true;
1887
+ seen.add(cur.name);
1888
+ if (!Object.prototype.hasOwnProperty.call(subst, cur.name)) return true;
1889
+ cur = subst[cur.name];
1890
+ }
1891
+
1892
+ return false;
1893
+ }
1894
+
1878
1895
  function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
1879
1896
  const g = applySubstTriple(goal, subst);
1880
1897
  const pv = iriValue(g.p);
@@ -3341,7 +3358,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
3341
3358
  // Schema: $s+ log:rawType $o-
3342
3359
  // Returns one of log:Formula, log:Literal, rdf:List, or log:Other.
3343
3360
  if (pv === LOG_NS + 'rawType') {
3344
- if (g.s instanceof Var) return [];
3361
+ if (g.s instanceof Var && !__varCameFromBoundSubstitution(goal.s, subst)) return [];
3345
3362
 
3346
3363
  let ty;
3347
3364
  if (g.s instanceof GraphTerm) ty = internIri(LOG_NS + 'Formula');