Skip to content

Commit 5506079

Browse files
hyperpolymathclaude
andcommitted
spec: add system specifications for VeriSimDB, Lithoglyph, TypeQL-Exp
Memory models, concurrency architectures, effect systems, and module structures for all three database projects. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8b98bc0 commit 5506079

3 files changed

Lines changed: 426 additions & 0 deletions

File tree

lithoglyph/spec/system-specs.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
4+
# Lithoglyph/GQL System Specification
5+
6+
## Overview
7+
8+
Lithoglyph is a graph query language database built on a polyglot stack:
9+
Forth (storage), Factor (query runtime), Zig (bridge), Elixir (control
10+
plane), and Lean 4 (normalizer).
11+
12+
## Memory Model
13+
14+
### Forth Storage Layer
15+
16+
The storage engine uses fixed-size blocks (4 KiB default, configurable at
17+
init). All writes are append-only: mutations produce new journal entries
18+
rather than overwriting existing blocks. Block addresses are immutable
19+
once allocated. Freed blocks are reclaimed only during explicit compaction.
20+
21+
### Zig Block Allocator
22+
23+
Zig manages the physical block pool via a slab allocator. Each slab
24+
corresponds to a memory-mapped region of the journal file. The allocator
25+
maintains a free-list of reclaimed blocks after compaction. A write-ahead
26+
log (WAL) in Zig ensures crash recovery: every block write is first
27+
recorded in the WAL, then flushed to the journal. WAL entries are
28+
checksummed (xxHash64) and trimmed after journal sync.
29+
30+
### Factor Query Execution
31+
32+
Factor executes queries using stack-based evaluation with no heap garbage
33+
collector. Intermediate query results live on the data stack or in
34+
explicitly allocated retain stacks. Large result sets spill to Zig-managed
35+
temporary blocks rather than growing unbounded in-process memory. Stack
36+
frames are released deterministically when a query completes.
37+
38+
### Lean 4 Normalizer
39+
40+
The Lean 4 normalizer operates on an in-memory graph representation
41+
received via serialized messages from the Elixir control plane. It
42+
performs graph rewriting in pure Lean (no IO monad) and returns the
43+
normalized form. Memory is managed by Lean's reference-counted runtime;
44+
the normalizer process is short-lived per invocation.
45+
46+
## Concurrency Model
47+
48+
### Elixir/OTP Session Management
49+
50+
Each client connection is supervised by an OTP GenServer. The supervisor
51+
tree uses `one_for_one` strategy: a crashed session does not affect
52+
others. Sessions hold no shared mutable state; all coordination happens
53+
through message passing to the storage coordinator (a singleton GenServer
54+
that serializes journal writes).
55+
56+
### Factor Cooperative Multitasking
57+
58+
Query execution within Factor uses cooperative multitasking via explicit
59+
yield points. Long-running traversals yield after processing each batch
60+
of edges (default batch size: 1024). This prevents any single query from
61+
starving the runtime. Factor threads are M:1 (multiplexed onto the OTP
62+
scheduler thread that owns the Factor NIF).
63+
64+
### Write Serialization
65+
66+
All journal mutations are serialized through the Elixir storage
67+
coordinator. Reads are lock-free against the append-only journal:
68+
readers see a consistent snapshot defined by the journal offset at
69+
query start (snapshot isolation via offset bookmarking).
70+
71+
## Effect System
72+
73+
### Provenance Effect (Mandatory)
74+
75+
Every mutation carries a provenance record as a mandatory effect. The
76+
provenance includes: actor identity (session ID + authenticated principal),
77+
timestamp (monotonic + wall-clock), rationale (client-supplied text or
78+
`"implicit"` default), and causal predecessor (previous journal offset
79+
for the affected subgraph). Provenance records are stored inline in the
80+
journal block, not in a side table. Queries may filter or project on
81+
provenance fields.
82+
83+
### Reversibility Effect
84+
85+
Every mutation also stores its inverse operation in the journal. For
86+
node insertion, the inverse is a tombstone marker. For edge creation,
87+
the inverse is edge removal. For property updates, the inverse stores
88+
the prior value. Reversal is triggered by issuing a `REVERT` command
89+
referencing a journal offset range. The reversal itself produces new
90+
journal entries (with their own provenance), preserving the append-only
91+
invariant.
92+
93+
### Effect Composition
94+
95+
Provenance and reversibility compose: reverting a mutation produces a
96+
new provenance record attributing the revert to the requesting actor,
97+
and the revert entry itself is reversible (enabling undo-of-undo).
98+
99+
## Module System
100+
101+
### Forth Word Definitions
102+
103+
Storage operations are defined as Forth words in `.4th` files loaded at
104+
engine startup. Custom words extend the storage vocabulary (e.g.,
105+
`BLOCK-ALLOC`, `WAL-APPEND`, `JOURNAL-SYNC`). Words are organized into
106+
wordlists by functional area.
107+
108+
### Factor Vocabularies
109+
110+
Query operations are organized as Factor vocabularies: `gql.parser`,
111+
`gql.planner`, `gql.executor`, `gql.results`. Each vocabulary declares
112+
its imports explicitly. Vocabularies are loaded on demand by the runtime.
113+
114+
### Elixir OTP Applications
115+
116+
The control plane is structured as an OTP umbrella application with
117+
child apps: `lithoglyph_session`, `lithoglyph_storage`,
118+
`lithoglyph_normalizer` (Lean 4 port wrapper), and `lithoglyph_api`
119+
(external interface). Dependencies between apps are declared in
120+
`mix.exs` and enforced by the release build.
121+
122+
### Cross-Language Boundaries
123+
124+
Zig serves as the bridge between Forth, Factor, and Elixir via NIF
125+
bindings. The Zig bridge exposes a C ABI consumed by Erlang NIFs and
126+
Factor FFI. Message formats crossing the bridge are length-prefixed
127+
binary with a 1-byte tag discriminator.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
4+
# TypeQL-Experimental System Specification
5+
6+
## Overview
7+
8+
TypeQL-Experimental is a research-stage type-theoretic query language
9+
that enforces resource safety, session protocols, and proof obligations
10+
at compile time. The stack comprises Idris2 (type kernel and effect
11+
enforcement), ReScript (parser), and Zig (FFI bridge).
12+
13+
## Memory Model
14+
15+
### Idris2 Type Kernel
16+
17+
Through Quantitative Type Theory (QTT), types with quantity `0` are
18+
erased at compile time and occupy no runtime memory. Proof terms exist
19+
only during type checking. Runtime values use Idris2's reference-counted
20+
backend (Chez Scheme or RefC). The kernel is invoked as a compile-time
21+
tool, so memory pressure is bounded by program size.
22+
23+
### ReScript Parser
24+
25+
The parser runs on the JS heap (Deno runtime). Source text is tokenized
26+
into an immutable AST (ReScript variant types), serialized to JSON for
27+
handoff to Idris2. Parser memory is short-lived: each invocation
28+
allocates, serializes, and releases. No persistent state between calls.
29+
30+
### Zig FFI Bridge
31+
32+
The bridge uses per-invocation arena allocators, freed in bulk on call
33+
completion. This eliminates fragmentation and ensures deterministic
34+
cleanup. Linear types in Idris2 guarantee that connection handles
35+
crossing the bridge are consumed exactly once.
36+
37+
### Linear Resource Guarantee
38+
39+
Connection handles, file descriptors, and transaction tokens are typed
40+
as `Linear a` (quantity `1`). The type checker verifies each linear
41+
resource is used exactly once. The Zig bridge asserts linearity at
42+
runtime via one-shot flags as defense-in-depth.
43+
44+
## Concurrency Model
45+
46+
TypeQL-Experimental is a compile-time research tool, not a runtime
47+
engine. There is no runtime concurrency model. The Idris2 checker is
48+
single-threaded, the ReScript parser synchronous, and the Zig bridge
49+
processes one invocation at a time. Build-time parallelism is delegated
50+
to `idris2 --threads` and `build.zig` parallel compilation.
51+
52+
## Effect System
53+
54+
Six typed effects, all enforced at compile time by Idris2 QTT.
55+
56+
### 1. Linear Consumption
57+
58+
Resources at quantity `1` must be consumed exactly once. Covers database
59+
connections, prepared statements, and result cursors. No resource leaks
60+
or double-frees are expressible in well-typed programs.
61+
62+
### 2. Session Protocol
63+
64+
Client-server interaction follows a session type (Idris2 indexed type)
65+
specifying the legal operation sequence: connect, authenticate, query,
66+
commit/rollback, disconnect. Deviating from the protocol is a type
67+
error. Parameterized by authentication state.
68+
69+
### 3. Effect Subsumption
70+
71+
Effects form a lattice. Computations requiring fewer effects embed into
72+
contexts permitting more (covariant). Pure computations compose into
73+
effectful contexts without annotation. Lattice ordering checked during
74+
elaboration.
75+
76+
### 4. Modal Scoping
77+
78+
Computations carry a modality: `Compile` or `Runtime`. Compile-time
79+
proofs cannot reference runtime values. Erased terms (quantity `0`) are
80+
never demanded at runtime.
81+
82+
### 5. Proof Attachment
83+
84+
Query results carry proof witnesses (e.g., `NoInjection`) of statically
85+
verified properties. Proofs are erased at runtime (quantity `0`) but
86+
available during type checking for downstream composition.
87+
88+
### 6. Resource Budgeting
89+
90+
Effectful computations declare resource budgets (max allocations, max
91+
recursion depth). Checked statically via dependent types on naturals;
92+
enforced dynamically for data-dependent bounds. Violations produce a
93+
`BudgetExceeded` type-level error requiring explicit handling.
94+
95+
## Module System
96+
97+
### Idris2 Packages
98+
99+
Organized as `.ipkg` packages: `typeql-kernel` (type rules),
100+
`typeql-effects` (effect lattice), `typeql-session` (session protocol),
101+
`typeql-proofs` (proof combinators). Dependencies declared in `depends`.
102+
103+
### ReScript Modules
104+
105+
`Lexer.res` (tokenization), `Parser.res` (recursive descent), `Ast.res`
106+
(types), `Serializer.res` (AST to JSON). Interface files (`.resi`)
107+
define public APIs.
108+
109+
### Zig Build System
110+
111+
Built with `build.zig`: `bridge.zig` (entry points), `arena.zig`
112+
(allocator), `protocol.zig` (serialization), `linear_check.zig`
113+
(runtime linearity). Produces a shared library consumed by Idris2
114+
(`%foreign`) and ReScript (Deno FFI).
115+
116+
### Cross-Language Integration
117+
118+
Idris2 calls Zig via `%foreign "C:function_name,libbridge"`. ReScript
119+
calls Zig via `Deno.dlopen`. The shared library exposes a flat C ABI
120+
with no global state; all functions take explicit context pointers.

0 commit comments

Comments
 (0)