eyeling 1.22.5 → 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 +258 -9
  2. package/dist/browser/eyeling.browser.js +162 -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 +162 -11
  34. package/lib/builtins.js +52 -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 +127 -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
 
@@ -2599,19 +2600,23 @@ In that sense, N3 is less a bid to make the web “smarter” than a bid to make
2599
2600
 
2600
2601
  <a id="app-c"></a>
2601
2602
 
2602
- ## Appendix C — N3 beyond Prolog: logic for RDF-style graphs
2603
+ ## Appendix C — N3 beyond Prolog: logic that survives the open web
2603
2604
 
2604
- Notation3 (N3) rule sets often look similar to Prolog at the surface: they use variables, unification, and implication-style rules (“if these patterns match, then these patterns follow”). N3 is typically used in a different setting: instead of a single program operating over a single local database, N3 rules and data are commonly written as documents that can be published, shared, merged, and referenced across systems.
2605
+ Notation3 and Prolog resemble each other at first glance. Both use variables, unification, and implication-shaped rules. Both can be used to derive consequences from a set of premises. But they were shaped for different native environments. Prolog was designed around executing logic programs. N3 was designed around expressing logic in the same world as RDF: a world of IRIs, triples, graphs, linked documents, and shared vocabularies. That difference in native setting gives N3 a wider built-in reach for web-scale knowledge work.
2605
2606
 
2606
- In practice, that setting is reflected in several common features of N3-style rule writing:
2607
+ The first difference is the data model. In Prolog, the basic units are terms and clauses. In N3, the basic units are RDF-style triples and graphs, extended with variables, lists, graph terms, and logical implication. N3 is explicitly defined as an extension of RDF, not as a separate programming language that merely happens to manipulate graphs. That means identifiers, data, and inferred results all live in one interoperable form. A rule consumes graph patterns and produces graph patterns, so the output of reasoning can be published, merged, quoted, exchanged, and reasoned over again without changing representation.
2607
2608
 
2608
- - **Identifiers are IRIs.** Terms are usually global identifiers rather than local symbols, which supports linking across datasets.
2609
- - **Input and output are graphs.** Rules consume graph patterns and produce additional triples, so the result of inference can be represented in the same form as the input data.
2610
- - **Quoted graphs allow statements-as-data.** N3 can treat a graph (a set of triples) as a term, which makes it possible to represent and reason about assertions (e.g., “this source says …” or “this formula implies …”) as data.
2611
- - **Rules can be distributed as text artifacts.** Rules can live alongside data, be versioned, and be reused without requiring an external host language to “carry” the meaning.
2612
- - **Built-ins cover common computations.** Many N3 workflows rely on built-ins for operations such as string handling, list processing, comparisons, and related utilities; some workflows also use IRIs as pointers to retrievable content.
2609
+ The second difference is more profound: N3 can treat graphs as first-class terms. A graph term is a quoted graph. It can appear in subject, predicate, or object position, and it does not automatically assert its contents as true. It is a resource in its own right. This makes it natural to represent claims, reports, beliefs, policies, source snapshots, and provenance. One can say not only “this is true,” but also “this document says this,” “this authority concludes that,” or “this rule applies to that quoted context.” In other words, N3 can reason about statements as statements, not only about the world those statements describe.
2613
2610
 
2614
- Engines can combine execution styles in different ways. One common pattern is to use a Prolog-like backward-chaining prover to satisfy rule bodies, while still using forward chaining to add the instantiated conclusions to the fact set until no new facts are produced.
2611
+ That leads directly to a third advantage: scope is part of the logic. In N3, implicit universal quantification is global, while implicit existential quantification is local to the graph in which it occurs. Once graphs can be nested and quoted, that distinction matters. It allows a reasoner to keep track of what is asserted here, what is asserted inside a quoted subgraph, and what variables belong to which level. This gives N3 a native way to express context-sensitive reasoning that would feel external or encoded-by-convention in classic Prolog.
2612
+
2613
+ A fourth difference is that N3 connects logic to the web inside the language itself. The N3 vocabulary includes `log:semantics` and `log:conclusion` for retrieving and reasoning over local or online sources. It also includes scoped operators such as `log:forAllIn` and `log:notIncludes`, which support scoped universal reasoning and scoped negation-as-failure over a chosen graph or document. So web retrieval, source-bounded reasoning, and reasoning over quoted content are not afterthoughts. They are part of the logic vocabulary. This is one of the clearest senses in which N3 has greater inherent potential: it is not only a language for deriving consequences from facts, but a language for locating, quoting, constraining, and comparing the sources of those facts.
2614
+
2615
+ By contrast, classic Prolog is centered on a proof procedure over definite clauses. In the usual operational reading, Prolog applies a restricted form of SLD-resolution, chooses the leftmost goal, tries clauses top-to-bottom, and searches depth-first. Traditional negation is negation-as-failure, described in the SWI-Prolog glossary as a weak negation. This makes Prolog extremely effective as an executable logic language, but it also means that much of its practical power comes from the operational behavior of the engine, not from a web-native knowledge model.
2616
+
2617
+ This does not make Prolog inferior. Modern Prolog systems add important capabilities beyond the classic core, including tabling, which improves termination behavior and can make Prolog behave more like a bottom-up theorem prover for some classes of problems. But that actually sharpens the comparison: when Prolog needs to work more comfortably in graph-heavy or knowledge-integration settings, it typically gains that power through extensions, libraries, or host-environment choices. N3 starts there. Graphs, quoted formulas, scoped reasoning, and web-connected semantics are part of its native conceptual center.
2618
+
2619
+ So the strongest claim is not that N3 replaces Prolog in every domain. The stronger and more precise claim is this: Prolog is a very strong language for executing logic programs, while N3 has greater inherent potential as a language for publishable, linkable, inspectable, and source-aware logic on the open web. It lets facts, rules, quoted claims, retrieved documents, and derived conclusions all live in one semantic space. For a system like Eyeling, that is not a cosmetic difference. It is the reason the language can scale from local inference to web-shaped reasoning without changing its basic form.
2615
2620
 
2616
2621
  ---
2617
2622
 
@@ -3153,6 +3158,9 @@ The following examples are especially useful if you want to see Eyeling files th
3153
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.
3154
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.
3155
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.
3156
3164
 
3157
3165
  #### Core ARC-style walkthroughs
3158
3166
 
@@ -3167,10 +3175,24 @@ The following examples are especially useful if you want to see Eyeling files th
3167
3175
 
3168
3176
  #### Technical and scientific ARC demos
3169
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.
3170
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.
3171
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.
3172
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.
3173
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
+
3174
3196
  #### Deep-classification stress tests
3175
3197
 
3176
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.
@@ -3256,3 +3278,230 @@ A good short summary is this:
3256
3278
  - Eyeling also defines a wider operational language than the current semantics document, especially through builtins and scoped proof/query features.
3257
3279
 
3258
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');
@@ -3988,6 +4005,23 @@
3988
4005
  results.push(s2);
3989
4006
  }
3990
4007
 
4008
+ // Also match quoted log:implies triples present as data in the current scope.
4009
+ if (facts && typeof facts.length === 'number') {
4010
+ ensureFactIndexes(facts);
4011
+ const pb = facts.__byPred.get(goal.p.__tid) || [];
4012
+ for (const idx of pb) {
4013
+ const tr = facts[idx];
4014
+
4015
+ let s2 = unifyTerm(goal.s, tr.s, subst);
4016
+ if (s2 === null) continue;
4017
+
4018
+ s2 = unifyTerm(goal.o, tr.o, s2);
4019
+ if (s2 === null) continue;
4020
+
4021
+ results.push(s2);
4022
+ }
4023
+ }
4024
+
3991
4025
  return results;
3992
4026
  }
3993
4027
 
@@ -4017,6 +4051,23 @@
4017
4051
  results.push(s2);
4018
4052
  }
4019
4053
 
4054
+ // Also match quoted log:impliedBy triples present as data in the current scope.
4055
+ if (facts && typeof facts.length === 'number') {
4056
+ ensureFactIndexes(facts);
4057
+ const pb = facts.__byPred.get(goal.p.__tid) || [];
4058
+ for (const idx of pb) {
4059
+ const tr = facts[idx];
4060
+
4061
+ let s2 = unifyTerm(goal.s, tr.s, subst);
4062
+ if (s2 === null) continue;
4063
+
4064
+ s2 = unifyTerm(goal.o, tr.o, s2);
4065
+ if (s2 === null) continue;
4066
+
4067
+ results.push(s2);
4068
+ }
4069
+ }
4070
+
4020
4071
  return results;
4021
4072
  }
4022
4073
 
@@ -4849,7 +4900,11 @@
4849
4900
 
4850
4901
  'use strict';
4851
4902
 
4903
+ const path = require('node:path');
4904
+ const { pathToFileURL } = require('node:url');
4905
+
4852
4906
  const engine = require('./engine');
4907
+ const deref = require('./deref');
4853
4908
  const { PrefixEnv } = require('./prelude');
4854
4909
 
4855
4910
  function offsetToLineCol(text, offset) {
@@ -4892,6 +4947,29 @@
4892
4947
  return fs.readFileSync(0, { encoding: 'utf8' });
4893
4948
  }
4894
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
+
4895
4973
  function main() {
4896
4974
  // Drop "node" and script name; keep only user-provided args
4897
4975
  // Expand combined short options: -pt == -p -t
@@ -5007,13 +5085,11 @@
5007
5085
  }
5008
5086
 
5009
5087
  const sourceLabel = useImplicitStdin || positional[0] === '-' ? '<stdin>' : positional[0];
5088
+ const baseIri = __sourceLabelToBaseIri(sourceLabel);
5089
+
5010
5090
  let text;
5011
5091
  try {
5012
- if (sourceLabel === '<stdin>') text = readTextFromStdinSync();
5013
- else {
5014
- const fs = require('node:fs');
5015
- text = fs.readFileSync(sourceLabel, { encoding: 'utf8' });
5016
- }
5092
+ text = __readInputSourceSync(sourceLabel);
5017
5093
  } catch (e) {
5018
5094
  if (sourceLabel === '<stdin>') console.error(`Error reading stdin: ${e.message}`);
5019
5095
  else console.error(`Error reading file ${JSON.stringify(sourceLabel)}: ${e.message}`);
@@ -5025,6 +5101,7 @@
5025
5101
  try {
5026
5102
  toks = engine.lex(text);
5027
5103
  const parser = new engine.Parser(toks);
5104
+ if (baseIri) parser.prefixes.setBase(baseIri);
5028
5105
  [prefixes, triples, frules, brules, qrules] = parser.parseDocument();
5029
5106
  // Make the parsed prefixes available to log:trace output (CLI path)
5030
5107
  engine.setTracePrefixes(prefixes);
@@ -5934,21 +6011,80 @@
5934
6011
  // -----------------------------------------------------------------------------
5935
6012
  // Used to maintain O(1) membership sets for dynamically promoted rules, and to
5936
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
+
5937
6063
  function __ruleKey(isForward, isFuse, premise, conclusion, dynamicConclusionTerm /* optional */) {
5938
6064
  let out = (isForward ? 'F' : 'B') + (isFuse ? '!' : '') + '|P|';
5939
6065
  for (let i = 0; i < premise.length; i++) {
5940
6066
  const tr = premise[i];
5941
6067
  if (i) out += '\n';
5942
- 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);
5943
6074
  }
5944
6075
  out += '|C|';
5945
6076
  for (let i = 0; i < conclusion.length; i++) {
5946
6077
  const tr = conclusion[i];
5947
6078
  if (i) out += '\n';
5948
- 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);
5949
6085
  }
5950
6086
  if (dynamicConclusionTerm) {
5951
- out += '|T|' + skolemKeyFromTerm(dynamicConclusionTerm);
6087
+ out += '|T|' + __keyFromTermForRuleIdentity(dynamicConclusionTerm);
5952
6088
  }
5953
6089
  return out;
5954
6090
  }
@@ -5959,7 +6095,12 @@
5959
6095
  for (let i = 0; i < instantiatedPremises.length; i++) {
5960
6096
  const tr = instantiatedPremises[i];
5961
6097
  if (i) out += '\n';
5962
- 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);
5963
6104
  }
5964
6105
  return out;
5965
6106
  }
@@ -8201,7 +8342,17 @@
8201
8342
  if (remaining <= 0) continue;
8202
8343
  const builtinMax = Number.isFinite(remaining) && !restGoals.length ? remaining : undefined;
8203
8344
 
8204
- let deltas = evalBuiltin(goal0, {}, facts, backRules, frame.curDepth, varGen, builtinMax);
8345
+ const builtinGoalForEval = goalPredicateIri === LOG_NS + 'rawType' ? rawGoal : goal0;
8346
+ const builtinSubstForEval = goalPredicateIri === LOG_NS + 'rawType' ? substMut : {};
8347
+ let deltas = evalBuiltin(
8348
+ builtinGoalForEval,
8349
+ builtinSubstForEval,
8350
+ facts,
8351
+ backRules,
8352
+ frame.curDepth,
8353
+ varGen,
8354
+ builtinMax,
8355
+ );
8205
8356
 
8206
8357
  const dc = typeof frame.deferCount === 'number' ? frame.deferCount : 0;
8207
8358
  const builtinDeltasAreVacuous = deltas.length > 0 && deltas.every((d) => Object.keys(d).length === 0);