eyeling 1.22.6 → 1.22.8

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 +188 -33
  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 +188 -33
  34. package/lib/builtins.js +18 -1
  35. package/lib/cli.js +31 -5
  36. package/lib/engine.js +139 -27
  37. package/package.json +1 -1
  38. package/test/api.test.js +100 -0
package/HANDBOOK.md CHANGED
@@ -32,6 +32,7 @@
32
32
  - [Appendix E — How Eyeling reaches 100% on `notation3tests`](#app-e)
33
33
  - [Appendix F — The ARC approach: Answer • Reason Why • Check](#app-f)
34
34
  - [Appendix G — Eyeling and the W3C CG Notation3 Semantics](#app-g)
35
+ - [Appendix H — Applied Constructor-Theory and the N3 ARC examples](#app-h)
35
36
 
36
37
  ---
37
38
 
@@ -3157,6 +3158,9 @@ The following examples are especially useful if you want to see Eyeling files th
3157
3158
  - [`examples/flandor.n3`](examples/flandor.n3) · [`examples/output/flandor.txt`](examples/output/flandor.txt) — macro-economic coordination case for Flanders that turns sensitive local signals into a regional retooling insight.
3158
3159
  - [`examples/medior.n3`](examples/medior.n3) · [`examples/output/medior.txt`](examples/output/medior.txt) — post-discharge care-coordination case that derives a minimal continuity-bundle insight without sharing the full record.
3159
3160
  - [`examples/parcellocker.n3`](examples/parcellocker.n3) · [`examples/output/parcellocker.txt`](examples/output/parcellocker.txt) — one-time parcel pickup authorization with a clear permit decision, justification, and misuse checks.
3161
+ - [`examples/harborsmr.n3`](examples/harborsmr.n3) · [`examples/output/harborsmr.txt`](examples/output/harborsmr.txt) — SMR flexibility case where private plant telemetry becomes a narrow, expiring electrolysis-dispatch insight with policy and safety checks.
3162
+
3163
+ - [`examples/transistor-switch.n3`](examples/transistor-switch.n3) · [`examples/output/transistor-switch.txt`](examples/output/transistor-switch.txt) — NPN low-side switch model with exact arithmetic and cutoff-versus-saturation checks.
3160
3164
 
3161
3165
  #### Core ARC-style walkthroughs
3162
3166
 
@@ -3171,10 +3175,24 @@ The following examples are especially useful if you want to see Eyeling files th
3171
3175
 
3172
3176
  #### Technical and scientific ARC demos
3173
3177
 
3178
+ - [`examples/fundamental-theorem-arithmetic.n3`](examples/fundamental-theorem-arithmetic.n3) · [`examples/output/fundamental-theorem-arithmetic.txt`](examples/output/fundamental-theorem-arithmetic.txt) — smallest-divisor prime factorization of 202692987 with ARC-style existence, uniqueness-up-to-order, and primality checks.
3179
+ - [`examples/complex-matrix-stability.n3`](examples/complex-matrix-stability.n3) · [`examples/output/complex-matrix-stability.txt`](examples/output/complex-matrix-stability.txt) — discrete-time stability classification for three diagonal complex 2×2 matrices via spectral radius and ARC-style checks.
3174
3180
  - [`examples/matrix-mechanics.n3`](examples/matrix-mechanics.n3) · [`examples/output/matrix-mechanics.txt`](examples/output/matrix-mechanics.txt) — small 2×2 matrix example deriving trace, determinant, products, and a non-zero commutator.
3175
3181
  - [`examples/pn-junction-tunneling.n3`](examples/pn-junction-tunneling.n3) · [`examples/output/pn-junction-tunneling.txt`](examples/output/pn-junction-tunneling.txt) — semiconductor toy model that explains current-proxy behavior across bias points.
3176
3182
  - [`examples/transistor-switch.n3`](examples/transistor-switch.n3) · [`examples/output/transistor-switch.txt`](examples/output/transistor-switch.txt) — NPN low-side switch model with exact arithmetic and cutoff-versus-saturation checks.
3177
3183
 
3184
+ #### Applied Constructor-Theory ARC examples
3185
+
3186
+ - [`examples/act-alarm-bit-interoperability.n3`](examples/act-alarm-bit-interoperability.n3) · [`examples/output/act-alarm-bit-interoperability.txt`](examples/output/act-alarm-bit-interoperability.txt) — applied constructor-theory information example showing interoperability of an alarm bit across unlike media together with a no-cloning contrast for a quantum token.
3187
+ - [`examples/act-docking-abort.n3`](examples/act-docking-abort.n3) · [`examples/output/act-docking-abort.txt`](examples/output/act-docking-abort.txt) — applied constructor-theory ARC case for a spacecraft docking-abort token covering permutation, copying, measurement, serial and parallel composition, and the impossibility of cloning a quantum seal.
3188
+ - [`examples/act-isolation-breach.n3`](examples/act-isolation-breach.n3) · [`examples/output/act-isolation-breach.txt`](examples/output/act-isolation-breach.txt) — applied constructor-theory ARC case for a biosafety isolation-breach token covering preparation, distinguishability, reversible permutation, copying, measurement, composition, and no-cloning.
3189
+ - [`examples/act-gravity-mediator-witness.n3`](examples/act-gravity-mediator-witness.n3) · [`examples/output/act-gravity-mediator-witness.txt`](examples/output/act-gravity-mediator-witness.txt) — applied constructor-theory witness showing that, under locality and interoperability, entanglement mediated only by gravity implies a non-classical gravitational mediator.
3190
+ - ['examples/act-yeast-self-reproduction.n3'](examples/act-yeast-self-reproduction.n3) · ['examples/output/act-yeast-self-reproduction.txt'](examples/output/act-yeast-self-reproduction.txt) — applied constructor-theory example of a yeast starter culture showing replicator, vehicle, self-reproduction, heritable variation, and natural selection under no-design laws.
3191
+ - ['examples/act-barley-seed-lineage.n3'](examples/act-barley-seed-lineage.n3) · ['examples/output/act-barley-seed-lineage.txt'](examples/output/act-barley-seed-lineage.txt) — applied constructor-theory ARC case showing both possible and impossible lineage tasks under no-design laws, including blocked reproduction, dormancy, and evolvability when key ingredients are missing.
3192
+ - ['examples/act-tunnel-junction-wake-switch.n3'](examples/act-tunnel-junction-wake-switch.n3) · ['examples/output/act-tunnel-junction-wake-switch.txt'](examples/output/act-tunnel-junction-wake-switch.txt) — applied constructor-theory ARC case comparing a tunnel-junction wake switch with a conventional PN junction via explicit can/can’t rules for tunneling, sub-threshold current, negative differential response, and low-bias switching.
3193
+ - ['examples/act-photosynthetic-exciton-transfer.n3'](examples/act-photosynthetic-exciton-transfer.n3) · ['examples/output/act-photosynthetic-exciton-transfer.txt'](examples/output/act-photosynthetic-exciton-transfer.txt) — applied constructor-theory ARC case for quantum-assisted exciton transfer in a photosynthetic antenna, contrasting a tuned complex with a detuned one via explicit can/can’t rules.
3194
+ - ['examples/act-sensor-memory-reset.n3'](examples/act-sensor-memory-reset.n3) · ['examples/output/act-sensor-memory-reset.txt'](examples/output/act-sensor-memory-reset.txt) — applied constructor-theory ARC case showing that a sensor memory reset is possible with a work medium but not with heat alone, highlighting work/heat distinction and irreversibility.
3195
+
3178
3196
  #### Deep-classification stress tests
3179
3197
 
3180
3198
  - [`examples/deep-taxonomy-10.n3`](examples/deep-taxonomy-10.n3) · [`examples/output/deep-taxonomy-10.txt`](examples/output/deep-taxonomy-10.txt) — ARC-style deep-taxonomy benchmark at depth 10.
@@ -3260,3 +3278,230 @@ A good short summary is this:
3260
3278
  - Eyeling also defines a wider operational language than the current semantics document, especially through builtins and scoped proof/query features.
3261
3279
 
3262
3280
  So the handbook and the semantics document are best read as complementary. The semantics document explains the abstract shape of Notation3. The handbook explains how a compact working reasoner realizes that shape, and where it chooses a practical execution model over a purely model-theoretic presentation.
3281
+
3282
+ <a id="app-h"></a>
3283
+
3284
+ ## Appendix H — Applied Constructor-Theory and the N3 ARC examples
3285
+
3286
+ This appendix explains the idea behind the **Applied Constructor-Theory** examples collected in the `examples/act-*` files.
3287
+
3288
+ The short version is:
3289
+
3290
+ > Appendix F explains the **presentation style** of ARC.
3291
+ > This appendix explains the **scientific style** of the ACT examples.
3292
+
3293
+ In this handbook, **ACT** is used as a practical label for examples that take constructor-theoretic ideas and turn them into concrete, runnable N3 programs. The label is local to this handbook: it is a convenient way to group examples that are about constructor theory in action, not a claim that there is one official file format or one officially standardized subfield called “ACT”.
3294
+
3295
+ ### H.1 What constructor theory is trying to do
3296
+
3297
+ Constructor theory is a proposal for formulating physics in terms of **which transformations are possible, which are impossible, and why**, rather than only in terms of trajectories and initial conditions.
3298
+
3299
+ That shift matters because many scientifically important statements already have that shape:
3300
+
3301
+ - information can be copied from one medium to another
3302
+ - an accurate self-reproducer can exist under no-design laws
3303
+ - a work medium can reset a memory in a way that heat alone cannot
3304
+ - a mediator that can entangle two quantum systems cannot be purely classical
3305
+
3306
+ Those are not merely predictions of one trajectory. They are statements about a space of **allowed and forbidden tasks**. Constructor theory is designed to make such statements fundamental rather than secondary.
3307
+
3308
+ ### H.2 Why this matters for applied examples
3309
+
3310
+ The constructor-theory programme is often presented through applications and research themes rather than as a closed symbolic calculus. In practice, that makes it a good fit for example-driven reasoning in Eyeling.
3311
+
3312
+ An Eyeling ACT example does not try to reproduce the full mathematical machinery of a physics paper. Instead, it extracts the **task structure** of the claim:
3313
+
3314
+ - what is being attempted
3315
+ - which resources or media are available
3316
+ - which structural conditions make the task possible
3317
+ - which missing conditions make the task impossible
3318
+ - what small set of checks would make the conclusion auditable
3319
+
3320
+ That is exactly the kind of thing N3 rules are good at expressing.
3321
+
3322
+ ### H.3 Why N3 fits constructor-theoretic reasoning unusually well
3323
+
3324
+ Notation3 is a good match for constructor-theoretic examples for four reasons.
3325
+
3326
+ First, N3 rules are naturally relational. They can say:
3327
+
3328
+ ```n3
3329
+ { ?system :has ?property . } => { ?system :can ?task . } .
3330
+ ```
3331
+
3332
+ and just as naturally:
3333
+
3334
+ ```n3
3335
+ { ?system :lacks ?property . } => { ?system :cannot ?task . } .
3336
+ ```
3337
+
3338
+ That is already close to the “science of can and can’t” idiom.
3339
+
3340
+ Second, N3 can keep the explanation close to the answer. The conditions, the derived `:can` / `:cannot` facts, and the final human-readable report can all live in one file.
3341
+
3342
+ Third, Eyeling supports `log:outputString`, so the result can be rendered as a compact ARC report rather than as a raw closure dump.
3343
+
3344
+ Fourth, Eyeling supports rule-based checks and hard fuses (`=> false`), so the example can state not only the claim but also what would count as a contradiction of the claim.
3345
+
3346
+ That combination makes N3 a strong medium for **pedagogical applied constructor theory**: it is executable, inspectable, and naturally counterfactual.
3347
+
3348
+ ### H.4 What these ACT examples are — and what they are not
3349
+
3350
+ These examples are **not** microscopic simulations.
3351
+
3352
+ They do not solve Schrödinger equations, semiconductor transport equations, or full biochemical kinetics. They are closer to **task-logic models**. They capture the counterfactual structure of a scientific claim:
3353
+
3354
+ - if these conditions hold, then this task is possible
3355
+ - if these conditions are absent, then that task is impossible
3356
+ - if the task is possible, what larger conclusion follows
3357
+ - if the task is impossible, what stronger claim is ruled out
3358
+
3359
+ That is why an ACT example often looks more like a carefully structured scientific argument than like a numerical simulator.
3360
+
3361
+ This is a feature, not a bug. The point is to model the **explanatory logic** of the claim in constructor-theoretic form.
3362
+
3363
+ ### H.5 The recurring shape of an ACT file in Eyeling
3364
+
3365
+ Most of the ACT files in this repository follow the same skeleton.
3366
+
3367
+ #### H.5.1 A concrete scenario
3368
+
3369
+ Each file starts with a scenario that is tangible enough to picture:
3370
+
3371
+ - an alarm bit crossing unlike media
3372
+ - a docking abort token
3373
+ - a biosafety isolation-breach signal
3374
+ - a gravitational mediator witness
3375
+ - a yeast or barley lineage
3376
+ - a tunnel-junction wake switch
3377
+ - a photosynthetic transfer complex
3378
+ - a sensor memory that must be reset
3379
+
3380
+ The point of the scenario is to stop constructor theory from floating away into abstract slogans.
3381
+
3382
+ #### H.5.2 Positive rules: what the system can do
3383
+
3384
+ The positive rules derive facts such as:
3385
+
3386
+ - `:can :Copy`
3387
+ - `:can :Measure`
3388
+ - `:can :AccurateSelfReproduction`
3389
+ - `:can :EfficientExcitonTransfer`
3390
+ - `:can :ReliableResetFromWork`
3391
+
3392
+ These are the constructor-theoretic heart of the file. They say which tasks become possible when the right structural conditions are present.
3393
+
3394
+ #### H.5.3 Negative rules: what the system cannot do
3395
+
3396
+ The negative rules derive facts such as:
3397
+
3398
+ - `:cannot :CloneAllStates`
3399
+ - `:cannot :AccurateSelfReproduction`
3400
+ - `:cannot :AdaptivePersistence`
3401
+ - `:cannot :ServeLeakAlarmWakeCircuit`
3402
+ - `:cannot :ReadyForReuseFromHeatAlone`
3403
+
3404
+ These rules matter just as much as the positive ones. A constructor-theoretic explanation is incomplete if it says only what works and never says what is ruled out.
3405
+
3406
+ In practice, the negative rules often provide the sharpest insight in the file.
3407
+
3408
+ #### H.5.4 An ARC report
3409
+
3410
+ The final rule usually emits a `log:outputString` report with three parts:
3411
+
3412
+ - **Answer**
3413
+ - **Reason Why**
3414
+ - **Check**
3415
+
3416
+ That is the Appendix F layer. ARC gives the file a readable surface. Constructor theory gives it the inner scientific logic.
3417
+
3418
+ #### H.5.5 Comments that explain the scientific role of each rule block
3419
+
3420
+ The better ACT examples are heavily commented. The comments should say not just what the syntax is doing, but what scientific role the block plays:
3421
+
3422
+ - interoperability
3423
+ - locality
3424
+ - no-cloning
3425
+ - replicator–vehicle logic
3426
+ - work versus heat
3427
+ - irreversibility
3428
+ - short-lived quantum assistance
3429
+ - blocked lineage closure
3430
+
3431
+ That is important because these examples are meant to teach a way of thinking, not only to demonstrate parser coverage.
3432
+
3433
+ ### H.6 The main constructor-theory themes represented in the examples
3434
+
3435
+ The current ACT examples are listed in Appendix F’s example catalog. This appendix is the conceptual companion to that list.
3436
+
3437
+ Here are the main themes those files illustrate.
3438
+
3439
+ #### H.6.1 Information as a task-level notion
3440
+
3441
+ The alarm-bit, docking-abort, and isolation-breach examples treat information as something that can be copied, permuted, measured, and moved between unlike media.
3442
+
3443
+ #### H.6.2 Life as accurate self-reproduction under no-design laws
3444
+
3445
+ The yeast and barley files follow the constructor-theory-of-life pattern: replication, self-reproduction, and natural selection are treated as tasks that can be possible under no-design laws when the right structural conditions are present.
3446
+
3447
+ These examples are especially good for N3 because the logic is already rule-shaped:
3448
+
3449
+ - digital heredity enables accurate copying
3450
+ - vehicle structure enables construction and repair
3451
+ - variation plus selection enables adaptive persistence
3452
+ - missing ingredients block those tasks
3453
+
3454
+ #### H.6.3 Thermodynamics as possible and impossible tasks
3455
+
3456
+ The sensor-memory-reset example is a compact way to express constructor-theoretic thermodynamics: a work-like resource can drive a reliable reset task that heat alone cannot, and an irreversible degradation path need not have the exact reverse available.
3457
+
3458
+ #### H.6.4 Non-classicality witnesses in hybrid systems
3459
+
3460
+ The gravity-mediator example shows how a constructor-theoretic application can be expressed as a chain of constraints: if locality and interoperability hold, and a mediator can entangle two quantum systems, then that mediator cannot be purely classical.
3461
+
3462
+ That kind of claim is perfect for N3 because it is already naturally expressed as a chain of conditions and consequences rather than as a trajectory simulation.
3463
+
3464
+ #### H.6.5 Quantum effects in practical settings
3465
+
3466
+ The tunnel-junction and photosynthetic-transfer files show how ACT examples can model quantum effects without pretending to be full microscopic calculations. They capture the counterfactual claim that certain structural conditions make a task possible, while contrast conditions block it.
3467
+
3468
+ This is often the right level of abstraction for a reasoning example: detailed enough to be about a real scientific idea, but explicit enough to stay executable and inspectable.
3469
+
3470
+ ### H.7 How to read an ACT example well
3471
+
3472
+ A good reading order is:
3473
+
3474
+ 1. identify the concrete application scenario
3475
+ 2. identify the `:can` facts the file is trying to establish
3476
+ 3. identify the `:cannot` facts that provide the contrast
3477
+ 4. read the final ARC report
3478
+ 5. go back and inspect the rule blocks that justify that report
3479
+ 6. check whether the file includes explicit validation or a fuse
3480
+
3481
+ That order preserves the scientific meaning of the example. You first see the task. Then you see the allowed and forbidden transformations. Only then do you look at the syntax in detail.
3482
+
3483
+ ### H.8 What makes a strong ACT example in this repository
3484
+
3485
+ A strong ACT example in Eyeling usually has five traits.
3486
+
3487
+ It is **concrete**. The reader can picture the system.
3488
+
3489
+ It is **counterfactual**. The file derives both a meaningful `:can` and a meaningful `:cannot`.
3490
+
3491
+ It is **commented at the scientific level**. The comments explain principles, not just syntax.
3492
+
3493
+ It is **ARC-shaped**. The answer, reason, and checks are visible.
3494
+
3495
+ And it is **honest about scope**. It does not pretend to be a full physical simulation when it is really a task-logic model.
3496
+
3497
+ ### H.9 Why keep these examples in the handbook at all
3498
+
3499
+ Because constructor theory can otherwise seem either too abstract or too grand.
3500
+
3501
+ The ACT examples solve that by making the ideas runnable. They let a reader see, in a small executable artifact, how a principle about possible and impossible tasks can be turned into explicit rules, explicit contrasts, and explicit checks.
3502
+
3503
+ That is valuable even for readers who do not plan to work on constructor theory itself. It shows a wider lesson:
3504
+
3505
+ > some scientific explanations are best understood not as “what happened once,” but as “what could be made to happen, what could not, and what structural features make the difference.”
3506
+
3507
+ That is exactly the sort of explanation that N3, and Eyeling in particular, can make unusually clear.
@@ -2359,6 +2359,23 @@
2359
2359
  // ===========================================================================
2360
2360
  // Backward proof & builtins mutual recursion — declarations first
2361
2361
 
2362
+ function __varCameFromBoundSubstitution(goalTerm, subst) {
2363
+ if (!(goalTerm instanceof Var)) return false;
2364
+ if (!subst || !Object.prototype.hasOwnProperty.call(subst, goalTerm.name)) return false;
2365
+
2366
+ let cur = subst[goalTerm.name];
2367
+ const seen = new Set([goalTerm.name]);
2368
+
2369
+ while (cur instanceof Var) {
2370
+ if (seen.has(cur.name)) return true;
2371
+ seen.add(cur.name);
2372
+ if (!Object.prototype.hasOwnProperty.call(subst, cur.name)) return true;
2373
+ cur = subst[cur.name];
2374
+ }
2375
+
2376
+ return false;
2377
+ }
2378
+
2362
2379
  function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
2363
2380
  const g = applySubstTriple(goal, subst);
2364
2381
  const pv = iriValue(g.p);
@@ -3834,7 +3851,7 @@
3834
3851
  // Schema: $s+ log:rawType $o-
3835
3852
  // Returns one of log:Formula, log:Literal, rdf:List, or log:Other.
3836
3853
  if (pv === LOG_NS + 'rawType') {
3837
- if (g.s instanceof Var) return [];
3854
+ if (g.s instanceof Var && !__varCameFromBoundSubstitution(goal.s, subst)) return [];
3838
3855
 
3839
3856
  let ty;
3840
3857
  if (g.s instanceof GraphTerm) ty = internIri(LOG_NS + 'Formula');
@@ -4883,7 +4900,11 @@
4883
4900
 
4884
4901
  'use strict';
4885
4902
 
4903
+ const path = require('node:path');
4904
+ const { pathToFileURL } = require('node:url');
4905
+
4886
4906
  const engine = require('./engine');
4907
+ const deref = require('./deref');
4887
4908
  const { PrefixEnv } = require('./prelude');
4888
4909
 
4889
4910
  function offsetToLineCol(text, offset) {
@@ -4926,6 +4947,29 @@
4926
4947
  return fs.readFileSync(0, { encoding: 'utf8' });
4927
4948
  }
4928
4949
 
4950
+ function __isNetworkOrFileIri(s) {
4951
+ return typeof s === 'string' && /^(https?:|file:\/\/)/i.test(s);
4952
+ }
4953
+
4954
+ function __sourceLabelToBaseIri(sourceLabel) {
4955
+ if (!sourceLabel || sourceLabel === '<stdin>') return '';
4956
+ if (__isNetworkOrFileIri(sourceLabel)) return deref.stripFragment(sourceLabel);
4957
+ return pathToFileURL(path.resolve(sourceLabel)).toString();
4958
+ }
4959
+
4960
+ function __readInputSourceSync(sourceLabel) {
4961
+ if (sourceLabel === '<stdin>') return readTextFromStdinSync();
4962
+
4963
+ if (__isNetworkOrFileIri(sourceLabel)) {
4964
+ const txt = deref.derefTextSync(sourceLabel);
4965
+ if (typeof txt !== 'string') throw new Error(`Failed to dereference ${sourceLabel}`);
4966
+ return txt;
4967
+ }
4968
+
4969
+ const fs = require('node:fs');
4970
+ return fs.readFileSync(sourceLabel, { encoding: 'utf8' });
4971
+ }
4972
+
4929
4973
  function main() {
4930
4974
  // Drop "node" and script name; keep only user-provided args
4931
4975
  // Expand combined short options: -pt == -p -t
@@ -5041,13 +5085,11 @@
5041
5085
  }
5042
5086
 
5043
5087
  const sourceLabel = useImplicitStdin || positional[0] === '-' ? '<stdin>' : positional[0];
5088
+ const baseIri = __sourceLabelToBaseIri(sourceLabel);
5089
+
5044
5090
  let text;
5045
5091
  try {
5046
- if (sourceLabel === '<stdin>') text = readTextFromStdinSync();
5047
- else {
5048
- const fs = require('node:fs');
5049
- text = fs.readFileSync(sourceLabel, { encoding: 'utf8' });
5050
- }
5092
+ text = __readInputSourceSync(sourceLabel);
5051
5093
  } catch (e) {
5052
5094
  if (sourceLabel === '<stdin>') console.error(`Error reading stdin: ${e.message}`);
5053
5095
  else console.error(`Error reading file ${JSON.stringify(sourceLabel)}: ${e.message}`);
@@ -5059,6 +5101,7 @@
5059
5101
  try {
5060
5102
  toks = engine.lex(text);
5061
5103
  const parser = new engine.Parser(toks);
5104
+ if (baseIri) parser.prefixes.setBase(baseIri);
5062
5105
  [prefixes, triples, frules, brules, qrules] = parser.parseDocument();
5063
5106
  // Make the parsed prefixes available to log:trace output (CLI path)
5064
5107
  engine.setTracePrefixes(prefixes);
@@ -5968,21 +6011,80 @@
5968
6011
  // -----------------------------------------------------------------------------
5969
6012
  // Used to maintain O(1) membership sets for dynamically promoted rules, and to
5970
6013
  // memoize per-firing head-blank skolemization.
6014
+ //
6015
+ // Important: variables and blank nodes *inside quoted formulas* are local to the
6016
+ // formula. Canonicalize those labels by first occurrence so alpha-equivalent
6017
+ // formulas (for example the repeated results of log:semantics after
6018
+ // standardize-apart) get the same identity key. Keep top-level blank labels
6019
+ // untouched so distinct existential witnesses in the global fact set do not
6020
+ // collapse together.
6021
+ function __keyFromTermForRuleIdentity(term) {
6022
+ const ctx = { quotedVar: new Map(), quotedBlank: new Map() };
6023
+
6024
+ function canonQuotedVar(name) {
6025
+ let out = ctx.quotedVar.get(name);
6026
+ if (!out) {
6027
+ out = `v${ctx.quotedVar.size}`;
6028
+ ctx.quotedVar.set(name, out);
6029
+ }
6030
+ return out;
6031
+ }
6032
+
6033
+ function canonQuotedBlank(label) {
6034
+ let out = ctx.quotedBlank.get(label);
6035
+ if (!out) {
6036
+ out = `b${ctx.quotedBlank.size}`;
6037
+ ctx.quotedBlank.set(label, out);
6038
+ }
6039
+ return out;
6040
+ }
6041
+
6042
+ function enc(u, inQuotedFormula) {
6043
+ if (u instanceof Iri) return ['I', u.value];
6044
+ if (u instanceof Literal) return ['L', u.value];
6045
+ if (u instanceof Blank) return inQuotedFormula ? ['BQ', canonQuotedBlank(u.label)] : ['B', u.label];
6046
+ if (u instanceof Var) return inQuotedFormula ? ['VQ', canonQuotedVar(u.name)] : ['V', u.name];
6047
+ if (u instanceof ListTerm) return ['List', u.elems.map((e) => enc(e, inQuotedFormula))];
6048
+ if (u instanceof OpenListTerm) {
6049
+ return [
6050
+ 'OpenList',
6051
+ u.prefix.map((e) => enc(e, inQuotedFormula)),
6052
+ inQuotedFormula ? ['TailVQ', canonQuotedVar(u.tailVar)] : ['TailV', u.tailVar],
6053
+ ];
6054
+ }
6055
+ if (u instanceof GraphTerm)
6056
+ return ['Graph', u.triples.map((tr) => [enc(tr.s, true), enc(tr.p, true), enc(tr.o, true)])];
6057
+ return ['Other', String(u)];
6058
+ }
6059
+
6060
+ return JSON.stringify(enc(term, false));
6061
+ }
6062
+
5971
6063
  function __ruleKey(isForward, isFuse, premise, conclusion, dynamicConclusionTerm /* optional */) {
5972
6064
  let out = (isForward ? 'F' : 'B') + (isFuse ? '!' : '') + '|P|';
5973
6065
  for (let i = 0; i < premise.length; i++) {
5974
6066
  const tr = premise[i];
5975
6067
  if (i) out += '\n';
5976
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
6068
+ out +=
6069
+ __keyFromTermForRuleIdentity(tr.s) +
6070
+ '\t' +
6071
+ __keyFromTermForRuleIdentity(tr.p) +
6072
+ '\t' +
6073
+ __keyFromTermForRuleIdentity(tr.o);
5977
6074
  }
5978
6075
  out += '|C|';
5979
6076
  for (let i = 0; i < conclusion.length; i++) {
5980
6077
  const tr = conclusion[i];
5981
6078
  if (i) out += '\n';
5982
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
6079
+ out +=
6080
+ __keyFromTermForRuleIdentity(tr.s) +
6081
+ '\t' +
6082
+ __keyFromTermForRuleIdentity(tr.p) +
6083
+ '\t' +
6084
+ __keyFromTermForRuleIdentity(tr.o);
5983
6085
  }
5984
6086
  if (dynamicConclusionTerm) {
5985
- out += '|T|' + skolemKeyFromTerm(dynamicConclusionTerm);
6087
+ out += '|T|' + __keyFromTermForRuleIdentity(dynamicConclusionTerm);
5986
6088
  }
5987
6089
  return out;
5988
6090
  }
@@ -5993,7 +6095,12 @@
5993
6095
  for (let i = 0; i < instantiatedPremises.length; i++) {
5994
6096
  const tr = instantiatedPremises[i];
5995
6097
  if (i) out += '\n';
5996
- out += skolemKeyFromTerm(tr.s) + '\t' + skolemKeyFromTerm(tr.p) + '\t' + skolemKeyFromTerm(tr.o);
6098
+ out +=
6099
+ __keyFromTermForRuleIdentity(tr.s) +
6100
+ '\t' +
6101
+ __keyFromTermForRuleIdentity(tr.p) +
6102
+ '\t' +
6103
+ __keyFromTermForRuleIdentity(tr.o);
5997
6104
  }
5998
6105
  return out;
5999
6106
  }
@@ -6553,14 +6660,44 @@
6553
6660
  }
6554
6661
  }
6555
6662
 
6556
- function collectProtectedNamesFromSubst(subst) {
6663
+ function collectProtectedNamesFromTermViaSubst(term, subst, protectedVars, protectedBlanks, seenVarNames) {
6664
+ if (term instanceof Var) {
6665
+ if (!subst || !Object.prototype.hasOwnProperty.call(subst, term.name)) return;
6666
+ if (seenVarNames.has(term.name)) return;
6667
+ seenVarNames.add(term.name);
6668
+ collectProtectedNamesInTerm(subst[term.name], protectedVars, protectedBlanks);
6669
+ return;
6670
+ }
6671
+
6672
+ if (term instanceof ListTerm) {
6673
+ for (const e of term.elems)
6674
+ collectProtectedNamesFromTermViaSubst(e, subst, protectedVars, protectedBlanks, seenVarNames);
6675
+ return;
6676
+ }
6677
+
6678
+ if (term instanceof OpenListTerm) {
6679
+ for (const e of term.prefix)
6680
+ collectProtectedNamesFromTermViaSubst(e, subst, protectedVars, protectedBlanks, seenVarNames);
6681
+ if (subst && Object.prototype.hasOwnProperty.call(subst, term.tailVar) && !seenVarNames.has(term.tailVar)) {
6682
+ seenVarNames.add(term.tailVar);
6683
+ collectProtectedNamesInTerm(subst[term.tailVar], protectedVars, protectedBlanks);
6684
+ }
6685
+ return;
6686
+ }
6687
+
6688
+ if (term instanceof GraphTerm) {
6689
+ for (const tr of term.triples) {
6690
+ collectProtectedNamesFromTermViaSubst(tr.s, subst, protectedVars, protectedBlanks, seenVarNames);
6691
+ collectProtectedNamesFromTermViaSubst(tr.p, subst, protectedVars, protectedBlanks, seenVarNames);
6692
+ collectProtectedNamesFromTermViaSubst(tr.o, subst, protectedVars, protectedBlanks, seenVarNames);
6693
+ }
6694
+ }
6695
+ }
6696
+
6697
+ function collectProtectedNamesForTerm(term, subst) {
6557
6698
  const protectedVars = new Set();
6558
6699
  const protectedBlanks = new Set();
6559
- if (!subst) return { protectedVars, protectedBlanks };
6560
- for (const k in subst) {
6561
- if (!Object.prototype.hasOwnProperty.call(subst, k)) continue;
6562
- collectProtectedNamesInTerm(subst[k], protectedVars, protectedBlanks);
6563
- }
6700
+ collectProtectedNamesFromTermViaSubst(term, subst, protectedVars, protectedBlanks, new Set());
6564
6701
  return { protectedVars, protectedBlanks };
6565
6702
  }
6566
6703
 
@@ -7522,6 +7659,9 @@
7522
7659
  }
7523
7660
 
7524
7661
  function unifyTermWithOptions(a, b, subst, opts) {
7662
+ const aRaw = a;
7663
+ const bRaw = b;
7664
+
7525
7665
  a = applySubstTerm(a, subst);
7526
7666
  b = applySubstTerm(b, subst);
7527
7667
 
@@ -7629,13 +7769,14 @@
7629
7769
 
7630
7770
  // Graphs
7631
7771
  if (a instanceof GraphTerm && b instanceof GraphTerm) {
7632
- const protectedNames = collectProtectedNamesFromSubst(subst);
7772
+ const protectedNamesA = collectProtectedNamesForTerm(aRaw, subst);
7773
+ const protectedNamesB = collectProtectedNamesForTerm(bRaw, subst);
7633
7774
  if (
7634
7775
  alphaEqGraphTriples(a.triples, b.triples, {
7635
- protectedVarsA: protectedNames.protectedVars,
7636
- protectedVarsB: protectedNames.protectedVars,
7637
- protectedBlanksA: protectedNames.protectedBlanks,
7638
- protectedBlanksB: protectedNames.protectedBlanks,
7776
+ protectedVarsA: protectedNamesA.protectedVars,
7777
+ protectedVarsB: protectedNamesB.protectedVars,
7778
+ protectedBlanksA: protectedNamesA.protectedBlanks,
7779
+ protectedBlanksB: protectedNamesB.protectedBlanks,
7639
7780
  })
7640
7781
  ) {
7641
7782
  return subst;
@@ -7939,6 +8080,9 @@
7939
8080
  }
7940
8081
 
7941
8082
  function unifyTermTrail(a, b) {
8083
+ const aRaw = a;
8084
+ const bRaw = b;
8085
+
7942
8086
  a = applySubstTerm(a, substMut);
7943
8087
  b = applySubstTerm(b, substMut);
7944
8088
 
@@ -8016,24 +8160,25 @@
8016
8160
 
8017
8161
  // Graphs
8018
8162
  if (a instanceof GraphTerm && b instanceof GraphTerm) {
8019
- const protectedNames = collectProtectedNamesFromSubst(substMut);
8163
+ const protectedNamesA = collectProtectedNamesForTerm(aRaw, substMut);
8164
+ const protectedNamesB = collectProtectedNamesForTerm(bRaw, substMut);
8020
8165
  if (
8021
8166
  alphaEqGraphTriples(a.triples, b.triples, {
8022
- protectedVarsA: protectedNames.protectedVars,
8023
- protectedVarsB: protectedNames.protectedVars,
8024
- protectedBlanksA: protectedNames.protectedBlanks,
8025
- protectedBlanksB: protectedNames.protectedBlanks,
8167
+ protectedVarsA: protectedNamesA.protectedVars,
8168
+ protectedVarsB: protectedNamesB.protectedVars,
8169
+ protectedBlanksA: protectedNamesA.protectedBlanks,
8170
+ protectedBlanksB: protectedNamesB.protectedBlanks,
8026
8171
  })
8027
8172
  ) {
8028
8173
  return true;
8029
8174
  }
8030
- // Fallback: reuse allocation-heavy graph unifier rarely hit in typical workloads.
8031
- const delta = unifyGraphTriples(a.triples, b.triples, {});
8032
- if (delta === null) return false;
8175
+ const merged = unifyGraphTriples(a.triples, b.triples, substMut);
8176
+ if (merged === null) return false;
8033
8177
  const mark = trail.length;
8034
- for (const k in delta) {
8035
- if (!Object.prototype.hasOwnProperty.call(delta, k)) continue;
8036
- if (!bindVarTrail(k, delta[k])) {
8178
+ for (const k in merged) {
8179
+ if (!Object.prototype.hasOwnProperty.call(merged, k)) continue;
8180
+ if (Object.prototype.hasOwnProperty.call(substMut, k)) continue;
8181
+ if (!bindVarTrail(k, merged[k])) {
8037
8182
  undoTo(mark);
8038
8183
  return false;
8039
8184
  }
@@ -8235,7 +8380,17 @@
8235
8380
  if (remaining <= 0) continue;
8236
8381
  const builtinMax = Number.isFinite(remaining) && !restGoals.length ? remaining : undefined;
8237
8382
 
8238
- let deltas = evalBuiltin(goal0, {}, facts, backRules, frame.curDepth, varGen, builtinMax);
8383
+ const builtinGoalForEval = goalPredicateIri === LOG_NS + 'rawType' ? rawGoal : goal0;
8384
+ const builtinSubstForEval = goalPredicateIri === LOG_NS + 'rawType' ? substMut : {};
8385
+ let deltas = evalBuiltin(
8386
+ builtinGoalForEval,
8387
+ builtinSubstForEval,
8388
+ facts,
8389
+ backRules,
8390
+ frame.curDepth,
8391
+ varGen,
8392
+ builtinMax,
8393
+ );
8239
8394
 
8240
8395
  const dc = typeof frame.deferCount === 'number' ? frame.deferCount : 0;
8241
8396
  const builtinDeltasAreVacuous = deltas.length > 0 && deltas.every((d) => Object.keys(d).length === 0);