# Cursor Logic: one relational substrate for SQLite, Lua, Nelua, JavaScript, and Scheme

> **Status:** architectural plan. The SQLite + Lua Cursor Machine and the parity-gated Nelua/Wasm core exist experimentally; the relational engine described here does not yet.
>
> **Central rule:** logic may explain and propose work. It does not silently create identity, authority, delivery, execution, or an external effect.

Cursor Logic is a bounded relational language for asking questions about Cursors and deriving new inspectable facts from existing evidence.

It is not a second database beside SQLite, a Prolog process hidden behind the cockpit, or a collection of language-specific object models. SQLite owns durable operational state and evaluator scheduling. Lua, S-expressions, JavaScript, Nelua, later Imba, Rust, Scheme, and other bodies all read and write one versioned term representation.

The intended shape is:

```text
canonical signed Cursors records
               |
               v
      SQLite operational body
  facts / rules / deltas / horizons
               |
       +-------+--------+
       |                |
       v                v
 bounded Datalog    Prolog-like queries
 fixpoint engine    variables + explanations
       |                |
       +-------+--------+
               v
      provenance / causal cone
               |
               v
     cockpit views and proposals
               |
       explicit authority gate
               |
               v
   continuation / envelope / effect
```

## Can SQLite control Datalog the way it controls Lua?

Yes, with a stronger fit than Lua in several places.

SQLite is already good at:

- durable fact and rule storage;
- indexed joins and selections;
- recursive common-table expressions for bounded recursive queries;
- transactions and snapshot isolation;
- work queues, leases, and generation checks;
- delta tables for semi-naive evaluation;
- materialized derived relations;
- query budgets, cancellation, and audit rows;
- virtual tables that project Cursors machinery into SQL;
- rebuilding operational indexes from canonical signed records.

The first Cursor Logic engine should therefore be **SQLite-owned**:

1. A transaction admits a bounded set of new or retracted facts.
2. SQLite freezes the input generation and causal horizon.
3. The scheduler selects rules affected by the delta.
4. An evaluator receives an immutable task packet containing relation IDs, rule IR, budgets, and input rows.
5. The evaluator returns relation deltas and derivation edges.
6. SQLite validates and commits those deltas atomically.
7. Subscriptions, guide embeds, and cockpit views observe the committed generation.

This is deliberately similar to the current coarse Lua continuation protocol. SQLite selects and leases work; a language body performs bounded pure computation; SQLite commits explicit results. Do not invoke arbitrary Lua or logic callbacks once per SQL row. That would combine poor crossing performance, reentrancy hazards, and a security boundary designed by committee.

### What SQLite should not do

SQLite should not become canonical signed protocol truth. CURSO records, grants, manifests, and receipts remain portable immutable material. SQLite stores verified bytes, indexes, projections, scheduler state, caches, leases, and provenance.

SQLite should also not expose unrestricted SQL handles to untrusted programs. Application-defined functions and virtual tables must be narrowly registered, deterministic where appropriate, and unavailable from untrusted schema objects. Production bodies should disable trusted schema execution and use the SQLite authorizer plus explicit statement limits.

## Datalog core, Prolog-like surface

Datalog is the correct semantic center because it is set-oriented, bottom-up, finite under a bounded term universe, incrementally maintainable, and naturally aligned with SQLite relations.

A Prolog-like surface is still useful for humans:

```prolog
ancestor(?cursor, ?ancestor).
resumable_on(?cursor, ?body).
missing_receipt(?cursor).
visible_via(?subject, ?curve, ?carrier).
why_resumed(?cursor, ?body).
```

The surface may offer variables, conjunction, bounded disjunction, pattern matching, and requests for one or more derivations. It compiles to the same relational intermediate representation as the Datalog and Lua forms.

Cursor Logic v0 does **not** include:

- `cut` or other search-order-dependent control;
- arbitrary dynamic clause assertion;
- host-language calls;
- unrestricted negation;
- unbounded term construction;
- ambient clock, filesystem, network, randomness, DOM, or SQLite access;
- a predicate that directly sends an envelope or performs an effect;
- depth-first search that can run forever while appearing thoughtfully occupied.

Later Scheme support may host a bounded miniKanren-like relational layer for synthesis and bidirectional interpreters. That remains a separate search engine over the same Cursor Terms and SQLite snapshots, not an excuse to weaken the Datalog core.

## Cursor Terms: one value model, several views

The integrated substrate needs one language-neutral term model.

Cursor Term v0 should include:

```text
null
boolean
integer
fixed decimal
symbol / atom
UTF-8 text
bytes
content reference / hash
logic variable
ordered tuple
list
record with named fields
constructor / form
explicit error
```

A term has several representations with distinct jobs:

| Representation | Job |
|---|---|
| CURSO canonical bytes | signatures, hashes, portable immutable identity |
| SQLite normalized rows | indexes, joins, deltas, provenance, horizons |
| Canonical S-expression | readable plans, rules, guides, fixtures |
| Plain Lua tables | restricted Lua and Nelua-facing programs |
| JavaScript/Imba values | browser reference evaluator and UI |
| Scheme values | later language-level implementation |

JSON remains diagnostic or live-edge material. It is not the signature authority.

A dataspace tuple, rule AST, continuation instruction, cryptofabric plan, capability caveat, and cockpit specimen should all be expressible as Cursor Terms. They remain different semantic types even when they share a representation.

## The same rule in three surfaces

### Datalog-like text

```prolog
ancestor(Child, Parent) :-
  parent(Child, Parent).

ancestor(Child, Ancestor) :-
  parent(Child, Parent),
  ancestor(Parent, Ancestor).
```

### Canonical S-expression

```scheme
(rule
  (ancestor ?child ?ancestor)
  (and
    (parent ?child ?parent)
    (ancestor ?parent ?ancestor)))
```

### Restricted Lua DSL

```lua
local V = logic.variables()

logic.rule {
  head = { "ancestor", V.child, V.ancestor },
  body = {
    { "parent", V.child, V.parent },
    { "ancestor", V.parent, V.ancestor },
  },
}
```

All three compile to the same immutable rule IR. None is stored as executable host-language source after compilation.

## Lua access to relations

Lua should see immutable plain tables and iterators, not raw database handles:

```lua
local parents = cursors.relation("parent")
  :at(horizon)
  :where { child = cursor_id }
  :limit(256)
  :rows()

for _, edge in ipairs(parents) do
  inspect(edge.parent)
end
```

Semantic writes are explicit intents:

```lua
cursors.assert {
  tuple = { "available", body_id },
  lease = lease_id,
}

cursors.interest {
  pattern = { "receipt", intent_id, logic.ANY },
}

cursors.derive {
  relation = "candidate_resume",
  tuple = { cursor_id, body_id },
  evidence = evidence_ids,
}
```

An effect request remains outside logic:

```lua
cursors.request_effect {
  intent_id = stable_intent_id,
  capability = grant_id,
  operation = "publish",
  resource = release_id,
}
```

SQLite then performs the existing capability, lease, idempotency, and receipt checks. A derived `candidate_resume` fact is not authority to resume.

## Proposed SQLite schema

This is a logical schema, not a frozen migration:

```sql
CREATE TABLE logic_programs (
  program_id TEXT PRIMARY KEY,
  version INTEGER NOT NULL,
  term_root BLOB NOT NULL,
  source_kind TEXT NOT NULL,
  status TEXT NOT NULL
);

CREATE TABLE logic_rules (
  program_id TEXT NOT NULL,
  rule_id TEXT NOT NULL,
  stratum INTEGER NOT NULL,
  rule_root BLOB NOT NULL,
  PRIMARY KEY (program_id, rule_id)
);

CREATE TABLE logic_horizons (
  horizon_id TEXT PRIMARY KEY,
  curve_id TEXT NOT NULL,
  generation INTEGER NOT NULL,
  observed_at INTEGER,
  evidence_class TEXT NOT NULL
);

CREATE TABLE logic_horizon_heads (
  horizon_id TEXT NOT NULL,
  cursor_id TEXT NOT NULL,
  PRIMARY KEY (horizon_id, cursor_id)
);

CREATE TABLE logic_facts (
  fact_id TEXT PRIMARY KEY,
  relation_id TEXT NOT NULL,
  tuple_root BLOB NOT NULL,
  horizon_id TEXT NOT NULL,
  source_cursor TEXT,
  source_body TEXT,
  lease_id TEXT,
  evidence_class TEXT NOT NULL,
  polarity INTEGER NOT NULL DEFAULT 1
);

CREATE INDEX logic_facts_relation_horizon
  ON logic_facts(relation_id, horizon_id);

CREATE TABLE logic_deltas (
  run_id TEXT NOT NULL,
  relation_id TEXT NOT NULL,
  tuple_root BLOB NOT NULL,
  weight INTEGER NOT NULL,
  PRIMARY KEY (run_id, relation_id, tuple_root)
);

CREATE TABLE logic_derivations (
  derivation_id TEXT PRIMARY KEY,
  output_fact_id TEXT NOT NULL,
  rule_id TEXT NOT NULL,
  horizon_id TEXT NOT NULL
);

CREATE TABLE logic_derivation_inputs (
  derivation_id TEXT NOT NULL,
  input_fact_id TEXT NOT NULL,
  ordinal INTEGER NOT NULL,
  PRIMARY KEY (derivation_id, ordinal)
);

CREATE TABLE logic_relation_policy (
  relation_id TEXT PRIMARY KEY,
  world_assumption TEXT NOT NULL,
  max_arity INTEGER NOT NULL,
  max_rows INTEGER NOT NULL,
  lease_required INTEGER NOT NULL,
  authority_profile TEXT
);

CREATE TABLE logic_runs (
  run_id TEXT PRIMARY KEY,
  program_id TEXT NOT NULL,
  input_horizon TEXT NOT NULL,
  output_horizon TEXT,
  evaluator_profile TEXT NOT NULL,
  step_budget INTEGER NOT NULL,
  row_budget INTEGER NOT NULL,
  status TEXT NOT NULL,
  receipt_id TEXT
);
```

Term nodes may use normalized tables or compact canonical blobs plus generated/index columns. Benchmark both. Do not normalize every scalar into a universal entity-attribute-value swamp unless the query workload proves it useful.

## Evaluator ladder

All engines consume identical Cursor Term, rule IR, task packet, result-delta, provenance, and error vectors.

### 1. JavaScript reference evaluator

The existing JavaScript evaluator remains the universal browser reference and no-Wasm fallback. It should be small, readable, deterministic, and heavily tested. The user-facing implementation may later be rewritten or optimized in Imba without changing the IR or expected results.

### 2. Nelua to C to Wasm first accelerator

Nelua is the first native/Wasm competitor because it fits the existing Lua/C/SQLite direction:

```text
Nelua source
   -> C
   -> native object or Emscripten Wasm
   -> parity gate against JavaScript vectors
```

The accelerator should begin with:

- term validation and canonical hashing;
- relation tuple decoding;
- indexed joins over bounded task packets;
- semi-naive delta loops;
- provenance edge compression;
- minisketch and fountain arithmetic where appropriate.

It receives no ambient authority and is admitted only after parity vectors pass.

### 3. Imba browser implementation

Imba may later replace or generate portions of the JavaScript evaluator and UI for ergonomics and performance. It remains the same semantic implementation family and must continue to run without Wasm.

### 4. Rust and other competitors

Rust arrives later as an independent implementation, not as the presumed winner. It competes on correctness, artifact size, startup, memory, SQLite crossing, optimizer quality, fuzzability, and maintainability.

### 5. Scheme language-level Cursors

A later Scheme profile should be capable of describing Cursor Terms, rules, continuations, and capability-scoped host calls in its own language facilities. Suggested direction:

- a named, versioned R7RS-small-like subset;
- hygienic macros compiling S-expressions to Cursor IR;
- optional miniKanren-style bounded relational search;
- no raw database, socket, file, or effect authority;
- all durable state and facts available through the same SQLite relations;
- conformance against JavaScript and Nelua vectors.

Scheme is valuable as a proof that the Cursors model is genuinely language-neutral and reflective. It should not become another mandatory runtime hidden under every deployment.

## Incremental evaluation

The first engine can use conventional semi-naive evaluation:

```text
new input delta
   -> rules touching changed relations
   -> joins using at least one delta input
   -> new relation delta
   -> repeat until fixed point or budget
```

SQLite can execute simple bounded recursion directly with recursive CTEs. More general stratified Datalog should compile to a relational plan and be orchestrated by the Cursor Machine.

Later work should compare:

- classic semi-naive evaluation;
- Differential Dataflow-style weighted changes;
- DBSP-style automatic incrementalization;
- specialized Nelua kernels;
- SQLite-native recursive plans;
- bottom-up versus bounded top-down queries.

The engine choice is replaceable. The committed facts, rule IR, horizons, and provenance are not.

## Provenance and causal questions

Every derived fact should retain at least one bounded derivation:

```text
candidate_resume(cursor-83, Mirror)
  because
    checkpoint(cursor-83, state-a91)
    body_available(Mirror)
    supports(Mirror, curso-continuation-v0)
    state_reachable(state-a91, local-store)
```

The cockpit can then answer:

- **Why is this true?** Show selected or minimal derivations.
- **What else could prove it?** Show alternative derivations.
- **Why did this happen?** Follow the durable causal cone into execution and receipts.
- **Why did this not happen?** Show missing prerequisites, failed caveats, expired leases, unavailable material, or an open-world boundary where absence proves nothing.

A provenance semiring is a useful conceptual model:

- multiplication means all listed facts were required by one derivation;
- addition means alternative derivations exist.

The implementation should store concrete signed fact IDs and derivation edges rather than only an opaque algebraic expression.

## Negation and absence

Distributed absence is treacherous. Cursor Logic must attach a world assumption to each relation:

| Policy | Meaning |
|---|---|
| `open` | absence means only “not established here” |
| `closed-at-horizon` | the relation is complete for this bounded snapshot |
| `leased-live` | absence may mean no currently live assertion was observed |
| `derived-closed` | completeness follows from a bounded input and terminating program |
| `authority-closed` | accepted trust roots define the complete policy set for this decision |

A `why not` query may conclude a negative fact only when the relevant relation is closed for the selected horizon. Otherwise the truthful answer is **unknown at this horizon**.

## Safety and budgets

Freeze explicit limits before running untrusted programs:

- term bytes, depth, arity, and collection size;
- facts and derived rows per relation;
- rules, strata, joins, and recursion rounds;
- query wall time and evaluator steps;
- provenance alternatives and proof depth;
- result count and output bytes;
- concurrent subscriptions;
- horizon heads and causal-cone size.

Reject unknown syntax and unsupported versions. Cancellation and budget exhaustion are deterministic result states, not engine crashes.

## Smallest executable milestone

Cursor Logic M0 should answer three queries over the existing SQLite + Lua Cursor Machine demo:

```prolog
ancestor(?cursor, ?ancestor).
candidate_resume(?cursor, ?body).
missing_receipt(?intent).
```

It should provide:

1. canonical S-expression and Lua DSL forms;
2. one versioned rule IR;
3. SQLite fact, delta, horizon, and provenance tables;
4. JavaScript reference evaluation;
5. a parity-gated Nelua/Wasm join kernel;
6. exact `why` derivations;
7. bounded `why not` explanations;
8. links from every fact and derivation to a real cockpit subject;
9. no ability to execute an effect.

## Acceptance criteria

- [ ] Lua, S-expression, and Prolog-like source compile to byte-equivalent rule IR.
- [ ] JavaScript and Nelua/Wasm return identical facts, errors, and selected provenance for frozen vectors.
- [ ] SQLite can rebuild derived relations after deleting all caches.
- [ ] Every evaluation is bound to an explicit causal horizon and curve.
- [ ] An open relation never turns missing data into a false global claim.
- [ ] A derived candidate cannot bypass capability presentation or effect receipts.
- [ ] Arbitrary Lua, JavaScript, Scheme, SQL, filesystem, network, DOM, clock, and randomness are unreachable from rules.
- [ ] Budget exhaustion, cancellation, unsupported syntax, and engine fallback are visible in the cockpit.
- [ ] Browser operation remains complete with Wasm and remote services unavailable.

## Research lineage

- [SQLite application-defined functions](https://sqlite.org/appfunc.html)
- [SQLite virtual tables](https://sqlite.org/vtab.html)
- [SQLite recursive CTEs](https://sqlite.org/lang_with.html)
- [SQLite authorizer](https://sqlite.org/c3ref/set_authorizer.html)
- [Dedalus: Datalog in Time and Space](https://www2.eecs.berkeley.edu/Pubs/TechRpts/2009/EECS-2009-173.html)
- [Conversational Concurrency / Syndicate](https://arxiv.org/abs/2409.04055)
- [Better Together: Unifying Datalog and Equality Saturation](https://arxiv.org/abs/2304.04332)
- [DBSP: Automatic Incremental View Maintenance](https://arxiv.org/abs/2203.16684)
- [Differential Dataflow](https://www.microsoft.com/en-us/research/publication/differential-dataflow/)
- [Datafun: a functional Datalog](https://doi.org/10.1145/3022670.2951948)
- [µKanren: A Minimal Functional Core for Relational Programming](https://webyrd.net/scheme-2013/papers/HemannMuKanren2013.pdf)
- [Provenance Semirings](https://doi.org/10.1145/1265530.1265535)

## Related Cursors guides and work

- [SQLite + Lua Cursor Machine](sqlite-lua-cursor-machine.md)
- [SQLite Body and Lua Programs](sqlite-body-and-lua-programs.md)
- [Nelua, Wasm, and the Portable Core](nelua-wasm-core.md)
- [Curved Dataspace](dataspace.md)
- [Capabilities](capabilities.md)
- [Cryptofabrics](cryptofabrics.md)
- [Causal Horizons and Why-Not](causal-horizons-and-why-not.md)
- [Cryptofabric Plans and Egglog](cryptofabric-plans-and-egglog.md)
