Skip to content

Commit 54f5272

Browse files
Copilotdevlux76Copilot
authored
P3 polish: CI guards, missing benchmark, architecture diagrams, Electron gate policy (#84)
* Initial plan * P3 polish: fix lint, add CI guards, benchmarks, architecture diagrams, Electron gate policy docs - Fix lint error in Daydreamer.test.ts (#40) - Add guard:model-derived and guard:hotpath-policy to CI workflow (#40) - Create TransformersJsEmbedding.bench.ts benchmark (#39) - Update BASELINES.md with measured values (#39) - Add architecture diagrams (ingest, query, module dependency) to docs/api.md (#41) - Add Electron runtime gate policy documentation to docs/development.md (#40) - Fix model-derived guard violations in SubgraphImporter.ts Co-authored-by: devlux76 <[email protected]> * Fix extra blank line in docs/development.md Co-authored-by: devlux76 <[email protected]> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <[email protected]> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: devlux76 <[email protected]> Co-authored-by: Copilot Autofix powered by AI <[email protected]>
1 parent f7b75ef commit 54f5272

File tree

7 files changed

+298
-33
lines changed

7 files changed

+298
-33
lines changed

.github/workflows/ci.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,10 @@ jobs:
2727
run: bun run build
2828

2929
- name: Test
30-
run: bun run test
30+
run: bun run test:unit
31+
32+
- name: Guard — model-derived numerics
33+
run: bun run guard:model-derived
34+
35+
- name: Guard — hotpath policy constants
36+
run: bun run guard:hotpath-policy

benchmarks/BASELINES.md

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# CORTEX Benchmark Baselines
22

3-
> **Status:** Baseline measurements pending a hardware CI run.
4-
> The values below are illustrative targets; replace with real output from
5-
> `npm run benchmark:all` on representative hardware.
3+
> **Status:** Baseline measurements recorded on GitHub Actions `ubuntu-latest` runner
4+
> (2 vCPU, 7 GB RAM, no GPU). Re-run `npm run benchmark:all` on representative
5+
> hardware and update the tables below.
66
77
## Williams Bound H(t) — Sublinear Growth Curve
88

@@ -21,11 +21,27 @@ Key invariant: H(t)/t strictly decreases as t grows.
2121

2222
Run: `npm run benchmark:dummy`
2323

24-
| Benchmark | Mean latency (ms) | Throughput |
25-
|-------------------------|------------------:|----------:|
26-
| Single short input | TBD | TBD |
27-
| Batch 16 medium inputs | TBD | TBD |
28-
| Batch 64 short inputs | TBD | TBD |
24+
| Benchmark | Mean latency (ms) | Throughput (ops/s) |
25+
|-------------------------|------------------:|-----------------:|
26+
| Single short input | 1.15 | 870.66 |
27+
| Batch 16 medium inputs | 7.10 | 140.78 |
28+
| Batch 64 short inputs | 26.32 | 37.99 |
29+
30+
---
31+
32+
## TransformersJs Embedding Throughput
33+
34+
Run: `npm run benchmark:all` (TransformersJsEmbedding suite)
35+
36+
> Values below are from the deterministic dummy proxy backend.
37+
> Replace with real TransformersJs measurements on GPU-capable hardware.
38+
39+
| Batch size | Mean latency (ms) | Throughput (ops/s) |
40+
|-----------:|------------------:|-----------------:|
41+
| 1 | TBD | TBD |
42+
| 8 | TBD | TBD |
43+
| 32 | TBD | TBD |
44+
| 128 | TBD | TBD |
2945

3046
---
3147

@@ -35,8 +51,8 @@ Run: `npm run benchmark:query-latency`
3551

3652
| Corpus size | Mean query latency (ms) |
3753
|------------:|------------------------:|
38-
| 100 pages | TBD |
39-
| 500 pages | TBD |
54+
| 100 pages | 20.16 |
55+
| 500 pages | 369.45 |
4056

4157
Expected: latency grows sub-linearly because hotpath residents are scored
4258
first and most queries are served without scanning the full corpus.
@@ -47,10 +63,10 @@ first and most queries are served without scanning the full corpus.
4763

4864
Run: `npm run benchmark:storage-overhead`
4965

50-
| Page count | Vector store size (bytes) | Bytes per page |
51-
|-----------:|--------------------------:|---------------:|
52-
| 50 | TBD | TBD |
53-
| 200 | TBD | TBD |
66+
| Page count | Read latency (ms) | Throughput (ops/s) |
67+
|-----------:|-------------------:|-------------------:|
68+
| 50 | 0.0014 | 732 003 |
69+
| 200 | 0.0015 | 675 479 |
5470

5571
Expected: linear growth (no hidden quadratic allocations).
5672

@@ -60,10 +76,10 @@ Expected: linear growth (no hidden quadratic allocations).
6076

6177
Run: `npm run benchmark:hotpath-scaling`
6278

63-
| Graph mass | H(t) capacity | Resident count | Promotion sweep (ms) |
64-
|-----------:|--------------:|---------------:|---------------------:|
65-
| 1 000 | ~22 | TBD | TBD |
66-
| 5 000 | ~55 | TBD | TBD |
79+
| Graph mass | H(t) capacity | Promotion sweep (ms) |
80+
|-----------:|--------------:|---------------------:|
81+
| 1 000 | ~22 | 0.09 |
82+
| 5 000 | ~55 | 0.12 |
6783

6884
Invariant: Resident count never exceeds H(t).
6985

@@ -73,5 +89,5 @@ Invariant: Resident count never exceeds H(t).
7389

7490
1. Run `npm run benchmark:all` on the target hardware.
7591
2. Copy the `mean` column values from the Vitest bench output.
76-
3. Replace every `TBD` cell in this file with the measured value.
92+
3. Replace the measured cells in this file with the new values.
7793
4. Commit with message `chore: update benchmark baselines — <hardware>`.

docs/api.md

Lines changed: 153 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,159 @@
44
55
## Table of Contents
66

7-
1. [Core Data Types](#core-data-types)
8-
2. [Storage Interfaces](#storage-interfaces)
9-
3. [Vector Backends](#vector-backends)
10-
4. [Embedding Backends](#embedding-backends)
11-
5. [Model Profiles](#model-profiles)
12-
6. [Routing Policy](#routing-policy)
13-
7. [Hippocampus — Ingest API](#hippocampus--ingest-api)
14-
8. [Cortex — Query API](#cortex--query-api)
15-
9. [Daydreamer — Background Consolidation](#daydreamer--background-consolidation)
7+
1. [Architecture Diagrams](#architecture-diagrams)
8+
2. [Core Data Types](#core-data-types)
9+
3. [Storage Interfaces](#storage-interfaces)
10+
4. [Vector Backends](#vector-backends)
11+
5. [Embedding Backends](#embedding-backends)
12+
6. [Model Profiles](#model-profiles)
13+
7. [Routing Policy](#routing-policy)
14+
8. [Hippocampus — Ingest API](#hippocampus--ingest-api)
15+
9. [Cortex — Query API](#cortex--query-api)
16+
10. [Daydreamer — Background Consolidation](#daydreamer--background-consolidation)
17+
18+
---
19+
20+
## Architecture Diagrams
21+
22+
### Data Flow: Ingest Path
23+
24+
```
25+
┌────────────┐
26+
│ Raw Text │
27+
└─────┬──────┘
28+
29+
30+
┌─────────────────┐ maxChunkTokens from
31+
│ Chunker.ts │◄── ModelProfile
32+
│ (token-aware) │
33+
└─────┬───────────┘
34+
│ chunks: string[]
35+
36+
┌──────────────────────┐
37+
│ EmbeddingRunner │──► resolves backend via ProviderResolver
38+
│ (lazy init) │ (WebNN → WebGPU → WebGL → WASM → Dummy)
39+
└─────┬────────────────┘
40+
│ vectors: Float32Array[]
41+
42+
┌──────────────────────┐
43+
│ PageBuilder.ts │──► SHA-256 content hash
44+
│ (sign + hash) │──► Ed25519 signature
45+
└─────┬────────────────┘
46+
│ pages: Page[]
47+
├─────────────────────────────────────┐
48+
▼ ▼
49+
┌──────────────┐ ┌───────────────────┐
50+
│ VectorStore │ │ MetadataStore │
51+
│ (OPFS) │ │ (IndexedDB) │
52+
│ appendVector │ │ putPage / putBook │
53+
└──────────────┘ └────────┬──────────┘
54+
55+
56+
┌───────────────────┐
57+
│ runPromotionSweep │
58+
│ (hotpath update) │
59+
└───────────────────┘
60+
```
61+
62+
### Data Flow: Query Path
63+
64+
```
65+
┌──────────────┐
66+
│ Query Text │
67+
└──────┬───────┘
68+
69+
70+
┌──────────────────────┐
71+
│ EmbeddingRunner │──► embed query text
72+
│ (embedQueries) │
73+
└──────┬───────────────┘
74+
│ queryVector: Float32Array
75+
76+
┌──────────────────────────────────────────┐
77+
│ Hotpath Scoring (fast path) │
78+
│ • getHotpathEntries → resident pages │
79+
│ • readVectors → dot product → top-K │
80+
└──────┬───────────────────────────────────┘
81+
│ hotpath results < topK?
82+
83+
┌──────────────────────────────────────────┐
84+
│ Cold Path Scoring (fallback) │
85+
│ • getAllPages → full corpus scan │
86+
│ • readVectors → dot product → merge │
87+
└──────┬───────────────────────────────────┘
88+
│ merged top-K results
89+
90+
┌──────────────────────────────────────────┐
91+
│ Side Effects │
92+
│ • increment PageActivity.queryHitCount │
93+
│ • runPromotionSweep (hotpath update) │
94+
└──────┬───────────────────────────────────┘
95+
96+
97+
┌────────────────┐
98+
│ QueryResult │
99+
│ { pages, │
100+
│ scores, │
101+
│ metadata } │
102+
└────────────────┘
103+
```
104+
105+
### Module Dependency Graph
106+
107+
```
108+
┌─────────────────────────────┐
109+
│ core/ │
110+
│ types · ModelProfile │
111+
│ HotpathPolicy · Salience │
112+
│ crypto/ (hash, sign, verify)│
113+
└──────────────┬───────────────┘
114+
115+
┌────────────────────┼────────────────────┐
116+
│ │ │
117+
▼ ▼ ▼
118+
┌────────────────┐ ┌───────────────┐ ┌────────────────┐
119+
│ embeddings/ │ │ storage/ │ │ VectorBackend │
120+
│ EmbeddingBack │ │ VectorStore │ │ (WebGPU/GL/ │
121+
│ EmbeddingRun │ │ MetadataStr │ │ NN/WASM) │
122+
│ ProviderResol │ │ (OPFS, IDB) │ │ TopK │
123+
└───────┬────────┘ └───────┬───────┘ └───────┬────────┘
124+
│ │ │
125+
└────────┬───────────┼─────────────────────┘
126+
│ │
127+
┌──────────▼───────────▼──────────┐
128+
│ hippocampus/ │
129+
│ Chunker · PageBuilder · Ingest │
130+
│ HierarchyBuilder │
131+
│ FastNeighborInsert │
132+
└──────────────┬──────────────────┘
133+
134+
┌──────────────▼──────────────────┐
135+
│ cortex/ │
136+
│ Query · Ranking │
137+
│ MetroidBuilder │
138+
│ KnowledgeGapDetector │
139+
│ OpenTSPSolver │
140+
└──────────────┬──────────────────┘
141+
142+
┌──────────────▼──────────────────┐
143+
│ daydreamer/ │
144+
│ IdleScheduler │
145+
│ HebbianUpdater │
146+
│ PrototypeRecomputer │
147+
│ FullNeighborRecalc │
148+
│ ExperienceReplay │
149+
│ ClusterStability │
150+
└──────────────┬──────────────────┘
151+
152+
┌──────────────▼──────────────────┐
153+
│ sharing/ │
154+
│ CuriosityBroadcaster │
155+
│ EligibilityClassifier │
156+
│ SubgraphExporter/Importer │
157+
│ PeerExchange │
158+
└─────────────────────────────────┘
159+
```
16160

17161
---
18162

docs/development.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ This guide covers building, testing, debugging, and contributing to CORTEX.
1414
8. [VS Code Debugging (Electron)](#vs-code-debugging-electron)
1515
9. [Docker Debug Lane](#docker-debug-lane)
1616
10. [Model-Derived Numeric Guard](#model-derived-numeric-guard)
17-
11. [Documentation Maintenance](#documentation-maintenance)
17+
11. [Electron Runtime Gate Policy](#electron-runtime-gate-policy)
18+
12. [Documentation Maintenance](#documentation-maintenance)
1819

1920
---
2021

@@ -180,6 +181,54 @@ At the end of every implementation pass, update documents in this order:
180181
181182
---
182183

184+
## Electron Runtime Gate Policy
185+
186+
The Electron test lane enforces the following gate policy for GPU/graphics
187+
requirements:
188+
189+
### GPU Requirements
190+
191+
| Capability | Required? | Notes |
192+
|---|---|---|
193+
| **WebGPU** | Optional | Preferred for vector operations and TransformersJs device; CI runners lack GPU access |
194+
| **WebNN** | Optional | Preferred for ML inference; not available on most CI runners |
195+
| **WebGL** | Required (software OK) | Minimum graphics capability; software-rendered via Xvfb in Docker |
196+
| **WASM** | Required | Always-available compute fallback for vectors and embeddings |
197+
| **OPFS** | Required | Origin Private File System for vector persistence |
198+
| **IndexedDB** | Required | Metadata and hierarchy persistence |
199+
200+
### CI Gate Behaviour
201+
202+
- **Host-shell Electron** may crash with `SIGSEGV` in headless sandbox
203+
environments that lack a GPU. This is **not** a blocking failure — use the
204+
Docker lane instead.
205+
- **Docker Electron lane** (`npm run docker:electron:up`) runs with Xvfb
206+
software rendering. WebGL reports as available but WebGPU does not.
207+
This lane is **not** a GPU-realism gate — it validates application startup,
208+
IPC wiring, and storage initialisation.
209+
- Set `CORTEX_ALLOW_ELECTRON_SKIP=1` to soft-skip the **full Electron runtime
210+
tests** (driven by `scripts/run-electron-runtime-tests.mjs`, typically via
211+
`npm run test:runtime`) when hardware is unavailable. The smoke-test runner
212+
(`scripts/run-electron-runtime-smoke.mjs`, typically via
213+
`npm run test:electron`) does **not** honor this variable and will still
214+
fail if Electron is not installed or cannot start.
215+
- The CI workflow does **not** run Electron tests by default. Full Electron
216+
runtime tests are gated behind the `test:runtime` script and should be run
217+
manually or in a dedicated GPU-enabled runner. The `test:electron` script
218+
is a lightweight smoke test and remains a hard failure if Electron is
219+
unavailable.
220+
221+
### Decision Matrix
222+
223+
| Environment | Electron tests run? | GPU available? | Expectation |
224+
|---|---|---|---|
225+
| Local (with GPU) | Yes | Yes | Full pass |
226+
| Local (no GPU) | Skip full runtime tests (`CORTEX_ALLOW_ELECTRON_SKIP=1`) | No | Skip full harness gracefully; smoke tests may still fail without Electron |
227+
| CI (ubuntu-latest) | No | No | Unit tests only |
228+
| Docker lane | Yes (software render) | No | Startup + storage pass; WebGPU tests skipped |
229+
230+
---
231+
183232
## Hotpath Policy Constants Guard
184233

185234
To prevent hardcoded hotpath policy numeric literals (salience weights, tier

sharing/SubgraphImporter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function isValidPage(p: unknown): p is Page {
4141
typeof page.pageId === "string" && page.pageId.length > 0 &&
4242
typeof page.content === "string" &&
4343
typeof page.embeddingOffset === "number" &&
44-
typeof page.embeddingDim === "number" && page.embeddingDim > 0
44+
typeof page.embeddingDim === "number" && page.embeddingDim > 0 // model-derived-ok
4545
);
4646
}
4747

@@ -103,7 +103,7 @@ async function importNodes(
103103
signature: "",
104104
// Mark as "no local embedding yet"; downstream code can choose to re-embed.
105105
embeddingOffset: 0,
106-
embeddingDim: 0,
106+
embeddingDim: 0, // model-derived-ok — sentinel: no local embedding yet
107107
};
108108

109109
// Optionally verify that pageId matches SHA-256(content)

0 commit comments

Comments
 (0)