init: tests, pyproject.toml, AGENTS.md, CLAUDE.md, README.md
This commit is contained in:
parent
b5989f35ec
commit
0a711b7688
10 changed files with 385 additions and 2 deletions
49
AGENTS.md
Normal file
49
AGENTS.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# CORE-AI Agent Instructions
|
||||
|
||||
## The Invariant (Read Before Touching Any Code)
|
||||
|
||||
Every field state F must satisfy:
|
||||
|
||||
||F * reverse(F) - 1||_F < 1e-6
|
||||
|
||||
This is checked by algebra/versor.py::versor_condition().
|
||||
|
||||
## What You Must Never Add
|
||||
|
||||
- Any normalization call outside ingest/gate.py
|
||||
- Grade guards, grade monitors, or grade projection in the hot path
|
||||
- Drift correction, correction thresholds, or correction timers
|
||||
- ANN indexes, HNSW, cosine similarity, or approximate distance
|
||||
- Field energy measurement or pseudoscalar accumulation checks
|
||||
- Any function whose only job is to watch or repair another function
|
||||
|
||||
If you think you need one of these, you have an unclosed operation upstream.
|
||||
Find it and close it.
|
||||
|
||||
## The Two Allowed Primitives
|
||||
|
||||
Field transition: algebra/versor.py::versor_apply(V, F) -> V*F*reverse(V)
|
||||
Distance metric: algebra/cga.py::cga_inner(X, Y) -> -d^2 / 2
|
||||
|
||||
These are the only primitives. Everything else is built from them.
|
||||
|
||||
## Implementation Order
|
||||
|
||||
Do not skip steps. Run the invariant test after each step before writing the next.
|
||||
|
||||
1. algebra/cl41.py
|
||||
2. algebra/versor.py -> tests/test_versor_closure.py must pass
|
||||
3. algebra/cga.py -> tests/test_null_cone.py must pass
|
||||
4. algebra/holonomy.py -> tests/test_holonomy.py must pass
|
||||
5. ingest/gate.py
|
||||
6. vocab/manifold.py
|
||||
7. field/state.py + field/propagate.py
|
||||
8. vault/store.py -> tests/test_vault_recall.py must pass
|
||||
9. persona/motor.py -> tests/test_motor.py must pass
|
||||
10. generate/stream.py
|
||||
11. session/context.py
|
||||
|
||||
## Architecture in One Sentence
|
||||
|
||||
Raw input -> inject once -> versor on the manifold -> versor_apply every step ->
|
||||
CGA inner product for recall and decoding -> persona motor for voicing -> done.
|
||||
33
CLAUDE.md
Normal file
33
CLAUDE.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# CORE-AI Agent Instructions
|
||||
|
||||
## The Invariant (Read Before Touching Any Code)
|
||||
|
||||
Every field state F must satisfy:
|
||||
|
||||
||F * reverse(F) - 1||_F < 1e-6
|
||||
|
||||
This is checked by algebra/versor.py::versor_condition().
|
||||
|
||||
## What You Must Never Add
|
||||
|
||||
- Any normalization call outside ingest/gate.py
|
||||
- Grade guards, grade monitors, or grade projection in the hot path
|
||||
- Drift correction, correction thresholds, or correction timers
|
||||
- ANN indexes, HNSW, cosine similarity, or approximate distance
|
||||
- Field energy measurement or pseudoscalar accumulation checks
|
||||
- Any function whose only job is to watch or repair another function
|
||||
|
||||
If you think you need one of these, you have an unclosed operation upstream.
|
||||
Find it and close it.
|
||||
|
||||
## The Two Allowed Primitives
|
||||
|
||||
Field transition: algebra/versor.py::versor_apply(V, F) -> V*F*reverse(V)
|
||||
Distance metric: algebra/cga.py::cga_inner(X, Y) -> -d^2 / 2
|
||||
|
||||
These are the only primitives. Everything else is built from them.
|
||||
|
||||
## Architecture in One Sentence
|
||||
|
||||
Raw input -> inject once -> versor on the manifold -> versor_apply every step ->
|
||||
CGA inner product for recall and decoding -> persona motor for voicing -> done.
|
||||
51
README.md
51
README.md
|
|
@ -1,2 +1,49 @@
|
|||
# core
|
||||
Versor Engine: a cognitive field system built on Cl(4,1) Clifford algebra. All state transitions are versor products — coherence is algebraic, never monitored. No grade guards, no drift correction, no ANN indexing. Memory recall via exact CGA inner product. Persona encoded as a rigid motor.
|
||||
# CORE-AI: Versor Engine
|
||||
|
||||
A cognitive field system built on Cl(4,1) Conformal Geometric Algebra.
|
||||
|
||||
**Core invariant:** `||F * reverse(F) - 1||_F < 1e-6` at all times.
|
||||
|
||||
All state is a versor. All transitions are versor products.
|
||||
Coherence is algebraic by construction — not monitored, not corrected.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
pip install -e ".[dev]"
|
||||
pytest tests/test_versor_closure.py # must pass before anything else
|
||||
pytest tests/
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
raw input -> ingest/gate.py (normalize once)
|
||||
-> field/propagate.py (versor_apply every step)
|
||||
-> generate/stream.py (nearest by cga_inner)
|
||||
-> vault/store.py (store and recall by cga_inner)
|
||||
-> persona/motor.py (rigid motor, not weight overlay)
|
||||
```
|
||||
|
||||
## The Two Primitives
|
||||
|
||||
- `versor_apply(V, F) = V * F * reverse(V)` — the only field transition
|
||||
- `cga_inner(X, Y) = -d^2 / 2` — the only distance metric
|
||||
|
||||
## Layers
|
||||
|
||||
| Layer | Purpose |
|
||||
|---|---|
|
||||
| `algebra/` | Cl(4,1) multivector math, versor ops, CGA, holonomy |
|
||||
| `ingest/` | Single injection gate — the only normalization site |
|
||||
| `field/` | FieldState dataclass and propagation loop |
|
||||
| `vocab/` | Word-to-versor manifold, edge rotors |
|
||||
| `vault/` | Exact CGA inner product memory store |
|
||||
| `persona/` | Persona as CGA motor (screw motion) |
|
||||
| `generate/` | Token streaming loop |
|
||||
| `session/` | Session binding: field + vault + vocab + persona |
|
||||
|
||||
## Signature
|
||||
|
||||
Cl(4,1): `(+, +, +, +, -)` — conformal model of 3D Euclidean space.
|
||||
Multivectors: `float32` arrays of shape `(32,)`, ordered by grade.
|
||||
|
|
|
|||
21
pyproject.toml
Normal file
21
pyproject.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[project]
|
||||
name = "core-ai"
|
||||
version = "0.1.0"
|
||||
description = "Versor Engine: cognitive field system on Cl(4,1) Conformal Geometric Algebra"
|
||||
requires-python = ">=3.11"
|
||||
|
||||
dependencies = [
|
||||
"numpy>=1.26",
|
||||
"mlx>=0.18; sys_platform == 'darwin'",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest>=8.0",
|
||||
"pytest-asyncio>=0.23",
|
||||
"hypothesis>=6.100",
|
||||
]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
asyncio_mode = "auto"
|
||||
testpaths = ["tests"]
|
||||
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
48
tests/test_holonomy.py
Normal file
48
tests/test_holonomy.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from algebra.versor import normalize_to_versor, versor_condition
|
||||
from algebra.holonomy import holonomy_encode, holonomy_similarity
|
||||
|
||||
|
||||
def _random_versors(n: int, seed: int = 0) -> list:
|
||||
rng = np.random.default_rng(seed)
|
||||
return [
|
||||
normalize_to_versor(rng.standard_normal(32).astype(np.float32))
|
||||
for _ in range(n)
|
||||
]
|
||||
|
||||
|
||||
def test_holonomy_is_versor():
|
||||
words = _random_versors(5)
|
||||
H = holonomy_encode(words)
|
||||
assert versor_condition(H) < 1e-5
|
||||
|
||||
|
||||
def test_holonomy_bounded_short():
|
||||
words = _random_versors(1)
|
||||
H = holonomy_encode(words)
|
||||
norm = float(np.linalg.norm(H))
|
||||
assert 0.1 < norm < 10.0, f"Holonomy norm out of range: {norm}"
|
||||
|
||||
|
||||
def test_holonomy_bounded_long():
|
||||
words = _random_versors(100)
|
||||
H = holonomy_encode(words)
|
||||
norm = float(np.linalg.norm(H))
|
||||
assert 0.1 < norm < 10.0, f"Long holonomy norm out of range: {norm}"
|
||||
|
||||
|
||||
def test_holonomy_distinguishes_prompts():
|
||||
words_a = _random_versors(5, seed=0)
|
||||
words_b = _random_versors(5, seed=99)
|
||||
Ha = holonomy_encode(words_a)
|
||||
Hb = holonomy_encode(words_b)
|
||||
sim = abs(holonomy_similarity(Ha, Hb))
|
||||
assert sim < 0.99, f"Two random prompts should be geometrically distinct, got sim={sim}"
|
||||
|
||||
|
||||
def test_holonomy_single_word():
|
||||
words = _random_versors(1)
|
||||
H = holonomy_encode(words)
|
||||
assert versor_condition(H) < 1e-5
|
||||
47
tests/test_motor.py
Normal file
47
tests/test_motor.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from algebra.versor import normalize_to_versor, versor_condition
|
||||
from persona.motor import PersonaMotor
|
||||
|
||||
|
||||
def _random_versor(seed=0) -> np.ndarray:
|
||||
rng = np.random.default_rng(seed)
|
||||
return normalize_to_versor(rng.standard_normal(32).astype(np.float32))
|
||||
|
||||
|
||||
def test_identity_motor_no_change():
|
||||
"""Identity motor returns input unchanged."""
|
||||
motor = PersonaMotor.identity()
|
||||
F = _random_versor(0)
|
||||
result = motor.apply(F)
|
||||
assert np.allclose(result, F, atol=1e-5)
|
||||
|
||||
|
||||
def test_motor_application_stays_on_manifold():
|
||||
"""Applying a motor keeps F on the versor manifold."""
|
||||
t = normalize_to_versor(_random_versor(1))
|
||||
r = normalize_to_versor(_random_versor(2))
|
||||
motor = PersonaMotor(t, r)
|
||||
F = _random_versor(3)
|
||||
result = motor.apply(F)
|
||||
assert versor_condition(result) < 1e-4
|
||||
|
||||
|
||||
def test_motor_composition_on_manifold():
|
||||
"""Composing two motors produces a motor on the manifold."""
|
||||
t1 = normalize_to_versor(_random_versor(0))
|
||||
r1 = normalize_to_versor(_random_versor(1))
|
||||
t2 = normalize_to_versor(_random_versor(2))
|
||||
r2 = normalize_to_versor(_random_versor(3))
|
||||
m1 = PersonaMotor(t1, r1)
|
||||
m2 = PersonaMotor(t2, r2)
|
||||
composed = m1.compose(m2)
|
||||
assert versor_condition(composed.M) < 1e-4
|
||||
|
||||
|
||||
def test_from_concept_vector():
|
||||
"""PersonaMotor.from_concept_vector should not raise and produces a valid motor."""
|
||||
concept = np.array([0.5, -0.3, 0.8], dtype=np.float32)
|
||||
motor = PersonaMotor.from_concept_vector(concept)
|
||||
assert versor_condition(motor.M) < 1e-4
|
||||
39
tests/test_null_cone.py
Normal file
39
tests/test_null_cone.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from algebra.cga import embed_point, is_null, null_project, cga_inner
|
||||
|
||||
|
||||
def test_embedded_point_is_null():
|
||||
x = np.array([1.0, 2.0, 3.0], dtype=np.float32)
|
||||
X = embed_point(x)
|
||||
assert is_null(X), f"Embedded point not null: cga_inner(X,X)={cga_inner(X,X):.2e}"
|
||||
|
||||
|
||||
def test_origin_is_null():
|
||||
X = embed_point(np.zeros(3, dtype=np.float32))
|
||||
assert is_null(X)
|
||||
|
||||
|
||||
def test_null_project_restores_null():
|
||||
x = np.array([1.0, 2.0, 3.0], dtype=np.float32)
|
||||
X = embed_point(x)
|
||||
rng = np.random.default_rng(0)
|
||||
X_drifted = X + rng.standard_normal(32).astype(np.float32) * 0.01
|
||||
X_fixed = null_project(X_drifted)
|
||||
assert is_null(X_fixed), f"null_project failed: {cga_inner(X_fixed, X_fixed):.2e}"
|
||||
|
||||
|
||||
def test_cga_inner_symmetry():
|
||||
X = embed_point(np.array([1.0, 0.0, 0.0]))
|
||||
Y = embed_point(np.array([0.0, 1.0, 0.0]))
|
||||
assert abs(cga_inner(X, Y) - cga_inner(Y, X)) < 1e-6
|
||||
|
||||
|
||||
def test_cga_inner_distance_identity():
|
||||
"""cga_inner(X, Y) = -d^2 / 2 for unit-distance points."""
|
||||
X = embed_point(np.array([0.0, 0.0, 0.0]))
|
||||
Y = embed_point(np.array([1.0, 0.0, 0.0]))
|
||||
inner = cga_inner(X, Y)
|
||||
# d=1, so expected = -0.5
|
||||
assert abs(inner - (-0.5)) < 1e-5, f"Expected -0.5, got {inner}"
|
||||
46
tests/test_vault_recall.py
Normal file
46
tests/test_vault_recall.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from algebra.versor import normalize_to_versor
|
||||
from algebra.cga import is_null
|
||||
from vault.store import VaultStore
|
||||
|
||||
|
||||
def _random_versor(seed=0) -> np.ndarray:
|
||||
rng = np.random.default_rng(seed)
|
||||
return normalize_to_versor(rng.standard_normal(32).astype(np.float32))
|
||||
|
||||
|
||||
def test_store_and_recall_top1():
|
||||
"""Each stored versor should recall itself as the top result."""
|
||||
vault = VaultStore()
|
||||
versors = [_random_versor(i) for i in range(20)]
|
||||
for i, v in enumerate(versors):
|
||||
vault.store(v, {"id": i})
|
||||
for i, v in enumerate(versors):
|
||||
results = vault.recall(v, top_k=1)
|
||||
assert results[0]["metadata"]["id"] == i, (
|
||||
f"Versor {i} did not recall itself as top result"
|
||||
)
|
||||
|
||||
|
||||
def test_recall_empty_vault():
|
||||
vault = VaultStore()
|
||||
result = vault.recall(_random_versor(), top_k=5)
|
||||
assert result == []
|
||||
|
||||
|
||||
def test_reproject_maintains_structure():
|
||||
"""Reproject should not lose stored entries."""
|
||||
vault = VaultStore()
|
||||
for i in range(10):
|
||||
vault.store(_random_versor(i), {"id": i})
|
||||
vault.reproject()
|
||||
assert len(vault) == 10
|
||||
|
||||
|
||||
def test_vault_len():
|
||||
vault = VaultStore()
|
||||
for i in range(5):
|
||||
vault.store(_random_versor(i))
|
||||
assert len(vault) == 5
|
||||
53
tests/test_versor_closure.py
Normal file
53
tests/test_versor_closure.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
"""
|
||||
CRITICAL: This test must pass before any other file is extended.
|
||||
It verifies the core algebraic invariant of the entire system.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from hypothesis import given, settings
|
||||
from hypothesis import strategies as st
|
||||
|
||||
from algebra.versor import versor_apply, normalize_to_versor, versor_condition
|
||||
|
||||
|
||||
def _random_versor(seed=None) -> np.ndarray:
|
||||
rng = np.random.default_rng(seed)
|
||||
raw = rng.standard_normal(32).astype(np.float32)
|
||||
return normalize_to_versor(raw)
|
||||
|
||||
|
||||
@given(st.integers(min_value=0, max_value=99))
|
||||
@settings(max_examples=100)
|
||||
def test_versor_apply_preserves_manifold(seed):
|
||||
"""V*F*reverse(V) must be a versor if V and F are versors."""
|
||||
V = _random_versor(seed)
|
||||
F = _random_versor(seed + 1000)
|
||||
result = versor_apply(V, F)
|
||||
cond = versor_condition(result)
|
||||
assert cond < 1e-4, f"versor_apply broke the manifold: condition={cond:.2e}"
|
||||
|
||||
|
||||
def test_normalize_produces_versor():
|
||||
raw = np.random.randn(32).astype(np.float32)
|
||||
V = normalize_to_versor(raw)
|
||||
assert versor_condition(V) < 1e-6
|
||||
|
||||
|
||||
def test_composition_closed():
|
||||
"""Two sequential versor_apply calls stay on the manifold."""
|
||||
V1 = _random_versor(0)
|
||||
V2 = _random_versor(1)
|
||||
F = _random_versor(2)
|
||||
F2 = versor_apply(V1, F)
|
||||
F3 = versor_apply(V2, F2)
|
||||
assert versor_condition(F3) < 1e-4
|
||||
|
||||
|
||||
def test_identity_versor():
|
||||
"""Scalar 1 is a valid versor and applies as identity."""
|
||||
identity = np.zeros(32, dtype=np.float32)
|
||||
identity[0] = 1.0
|
||||
F = _random_versor(42)
|
||||
result = versor_apply(identity, F)
|
||||
assert np.allclose(result, F, atol=1e-5)
|
||||
Loading…
Reference in a new issue