From b0771097ae4b84323d4d4343ba003a16f147eef0 Mon Sep 17 00:00:00 2001 From: Gerard Louis Recinto Date: Tue, 29 Sep 2026 01:13:18 -0700 Subject: [PATCH 1/4] wired: joltrinhq.com as the site domain, demo links and CNAME follow --- .github/workflows/deploy-demo.yml | 8 +++--- CNAME | 2 +- README.md | 28 +++++++++---------- sop-arena/README.md | 8 +++--- .../src/components/MissionSuccessModal.tsx | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/deploy-demo.yml b/.github/workflows/deploy-demo.yml index a120c9f8b..91f28ff60 100644 --- a/.github/workflows/deploy-demo.yml +++ b/.github/workflows/deploy-demo.yml @@ -107,13 +107,13 @@ jobs: set -euo pipefail rm -rf _site mkdir -p _site/arena _site/agents - # Technical demo (WASM) lives at the site root: sharedcode.github.io/joltrin/ + # Technical demo (WASM) lives at the site root: joltrinhq.com/ cp demo/index.html demo/sop.wasm demo/wasm_exec.js demo/404.html demo/favicon.svg demo/favicon.ico demo/og-image.png demo/logo-mark.png _site/ - # SOP Arena lives at a subpath of the same site: sharedcode.github.io/joltrin/arena/ + # SOP Arena lives at a subpath of the same site: joltrinhq.com/arena/ cp -r sop-arena/dist/. _site/arena/ - # Agent verification barrier (ai/verify in WASM) lives at sharedcode.github.io/joltrin/agents/ + # Agent verification barrier (ai/verify in WASM) lives at joltrinhq.com/agents/ cp demo-agents/index.html demo-agents/sop-agents.wasm demo-agents/wasm_exec.js demo-agents/favicon.svg demo-agents/favicon.ico demo-agents/og-image.png demo-agents/logo-mark.png _site/agents/ - # Preserve custom domain (e.g. joltrin.com) if CNAME exists + # Preserve custom domain (e.g. joltrinhq.com) if CNAME exists if [ -f "CNAME" ]; then cp CNAME _site/CNAME elif [ -f "demo/CNAME" ]; then diff --git a/CNAME b/CNAME index 77ed06066..bfe303b8f 100644 --- a/CNAME +++ b/CNAME @@ -1 +1 @@ -joltrin.com +joltrinhq.com diff --git a/README.md b/README.md index 36ded8e13..f1166ea09 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ [![Go Reference](https://pkg.go.dev/badge/github.com/sharedcode/joltrin/v5.svg)](https://pkg.go.dev/github.com/sharedcode/joltrin/v5) [![Go version](https://img.shields.io/github/go-mod/go-version/SharedCode/joltrin)](go.mod) [![License](https://img.shields.io/github/license/SharedCode/joltrin)](LICENSE) -[![Live Demos](https://img.shields.io/badge/Live_Demos-GitHub_Pages-10B981?logo=github)](https://sharedcode.github.io/joltrin/arena/) +[![Live Demos](https://img.shields.io/badge/Live_Demos-GitHub_Pages-10B981?logo=github)](https://joltrinhq.com/arena/) [![MCP](https://img.shields.io/badge/MCP-tools%2Fmcpserver-4A4A4A)](docs/MCP_A2A_AND_VERIFICATION_ENGINE.md) [![A2A](https://img.shields.io/badge/A2A-tools%2Fa2aagent-4A4A4A)](docs/MCP_A2A_AND_VERIFICATION_ENGINE.md) @@ -31,23 +31,23 @@ Instead of managing separate vector databases, message brokers, caching tiers, distributed lock managers, and fragile external checkpoint stores, Joltrin lets your AI agents maintain crash-resilient memory and enforce operational invariants directly within the execution boundary. > **Why "from milliseconds to microseconds"?** Traditional multi-tier architectures incur an estimated 15-50ms network round-trip penalty across external services (Redis, message queues, relational databases). Joltrin runs embedded in-process, shifting latency from milliseconds to microseconds: empirical benchmarks measure **<0.3ms** end-to-end in-process execution, **~6.87ยตs** per B-Tree write (>145,000 ops/sec), and **~6.95ยตs** per read (>143,000 ops/sec) with full ACID consistency. -> ๐Ÿ”— **Proof & Benchmark Reference:** [View Detailed Benchmarks & Microsecond Breakdown โ†’](#-performance-benchmarks) ยท Benchmark suite: [`tools/benchmark`](tools/benchmark) ยท Live client-side run: [Technical WASM Demo](https://sharedcode.github.io/joltrin/) +> ๐Ÿ”— **Proof & Benchmark Reference:** [View Detailed Benchmarks & Microsecond Breakdown โ†’](#-performance-benchmarks) ยท Benchmark suite: [`tools/benchmark`](tools/benchmark) ยท Live client-side run: [Technical WASM Demo](https://joltrinhq.com/)

Live Joltrin demo: in-process ACID transactions, distributed Arena simulation, and deterministic AI agent verification barrier

- ๐Ÿง  Launch Technical Demo โ†’   |   - ๐ŸŽฎ Play Joltrin Arena โ†’   |   - ๐Ÿ”Œ Launch Agent Barrier โ†’ + ๐Ÿง  Launch Technical Demo โ†’   |   + ๐ŸŽฎ Play Joltrin Arena โ†’   |   + ๐Ÿ”Œ Launch Agent Barrier โ†’

| Experience | Description | Live Interactive Link | | :--- | :--- | :--- | -| ๐Ÿง  **Joltrin Technical Demo** | **Client-Side Zero-Server WebAssembly Engine**
Execute live ACID transactions, 128-dimensional vector cosine searches, microsecond benchmarks, and durable AI agent memory checkpoints (kill the agent mid-task, watch a successor resume from the B-Tree) running 100% in your browser with **0 runtime HTTP network calls after initial load**. | [**Launch Technical Demo โ†’**](https://sharedcode.github.io/joltrin/) | -| ๐ŸŽฎ **Joltrin Arena** | **Distributed Systems Survival Simulation**
Command a live digital cluster. Scale worker swarms, crash storage nodes, trigger transaction storms, and watch Joltrin automatically redistribute tasks and rebuild parity in real-time. | [**Play Joltrin Arena โ†’**](https://sharedcode.github.io/joltrin/arena/) | -| ๐Ÿ”Œ **Joltrin Agent Verification Barrier** | **The MCP/A2A Safety Check, Clickable**
The same `ai/verify` barrier gating `tools/mcpserver` and `tools/a2aagent`, compiled to WASM. Try dropping a database before validating a backup and watch it get blocked, in your browser, with the trace persisted to OPFS. | [**Launch Agent Barrier โ†’**](https://sharedcode.github.io/joltrin/agents/) | +| ๐Ÿง  **Joltrin Technical Demo** | **Client-Side Zero-Server WebAssembly Engine**
Execute live ACID transactions, 128-dimensional vector cosine searches, microsecond benchmarks, and durable AI agent memory checkpoints (kill the agent mid-task, watch a successor resume from the B-Tree) running 100% in your browser with **0 runtime HTTP network calls after initial load**. | [**Launch Technical Demo โ†’**](https://joltrinhq.com/) | +| ๐ŸŽฎ **Joltrin Arena** | **Distributed Systems Survival Simulation**
Command a live digital cluster. Scale worker swarms, crash storage nodes, trigger transaction storms, and watch Joltrin automatically redistribute tasks and rebuild parity in real-time. | [**Play Joltrin Arena โ†’**](https://joltrinhq.com/arena/) | +| ๐Ÿ”Œ **Joltrin Agent Verification Barrier** | **The MCP/A2A Safety Check, Clickable**
The same `ai/verify` barrier gating `tools/mcpserver` and `tools/a2aagent`, compiled to WASM. Try dropping a database before validating a backup and watch it get blocked, in your browser, with the trace persisted to OPFS. | [**Launch Agent Barrier โ†’**](https://joltrinhq.com/agents/) | --- @@ -100,7 +100,7 @@ No revenue or customer numbers exist yet for this project (see [For Investors](# | **Stateful services to operate, patch, and page on** | Redis + Kafka/RabbitMQ + Postgres/Cassandra + ZooKeeper (4+) | 1 embedded library | | **Language surfaces shipped** | N/A | Go (native), Python (`sop4py` on PyPI), C# (`Sop` on NuGet); Java and Rust bindings exist in-repo with tests, not yet published | | **CI rigor on every change** | N/A | `govulncheck` clean on every push; race detector on the core engine packages (`btree`, `common`, `fs`, `inmemory`); 3-OS build and test matrix (Linux, macOS, Windows) | -| **Deployment footprint of the technical demo** | A server-backed demo stack | WASM build running ACID transactions, vector search, and agent-memory checkpointing 100% client-side, 0 runtime HTTP calls after page load ([live](https://sharedcode.github.io/joltrin/)) | +| **Deployment footprint of the technical demo** | A server-backed demo stack | WASM build running ACID transactions, vector search, and agent-memory checkpointing 100% client-side, 0 runtime HTTP calls after page load ([live](https://joltrinhq.com/)) | Every row above is something you can run yourself, not a projection. See [Performance Benchmarks](#-performance-benchmarks) for the throughput numbers behind the latency claim, and [What Has Not Yet Been Proven](#-for-investors) for what this table deliberately leaves out. @@ -108,7 +108,7 @@ Every row above is something you can run yourself, not a projection. See [Perfor ## ๐Ÿš€ Experience Joltrin -You can test Joltrin directly in your browser without installing anything via the live interactive experiences above ([Technical Demo](https://sharedcode.github.io/joltrin/), [Joltrin Arena](https://sharedcode.github.io/joltrin/arena/), and [Agent Verification Barrier](https://sharedcode.github.io/joltrin/agents/)). The technical demo demonstrates the engine's core power directly: safe, ACID-transactional storage running on web storage itself (OPFS), with zero server and zero network calls after the initial page loads the WASM binary. Everything else on this page, including the agent verification barrier below, is built on top of that same engine, a reference implementation showing one concrete use case. +You can test Joltrin directly in your browser without installing anything via the live interactive experiences above ([Technical Demo](https://joltrinhq.com/), [Joltrin Arena](https://joltrinhq.com/arena/), and [Agent Verification Barrier](https://joltrinhq.com/agents/)). The technical demo demonstrates the engine's core power directly: safe, ACID-transactional storage running on web storage itself (OPFS), with zero server and zero network calls after the initial page loads the WASM binary. Everything else on this page, including the agent verification barrier below, is built on top of that same engine, a reference implementation showing one concrete use case. The technical demo persists across reloads now, to Origin Private File System, via the browser's async File System Access API. The diagram below is the real tradeoff behind that choice, not a benchmark; no throughput numbers are shown because none have been measured for either path in this repo. @@ -128,7 +128,7 @@ Joltrin runbooks are reachable from two agent protocols, [Model Context Protocol An MCP client and an A2A orchestrator each reach a separate protocol server, both backed by the same tools/runbookstore.Store and gated by the same ai/verify safety check before a step commits

-**Try the barrier yourself, live: [sharedcode.github.io/joltrin/agents](https://sharedcode.github.io/joltrin/agents/).** GitHub Pages can't run a real MCP or A2A network server (no backend), so this page runs the actual `ai/verify` check compiled to WASM, wired to buttons instead of protocol calls, the same logic those servers call before committing a step. Click "Drop Prod DB" first and watch it block; the trace persists to OPFS, so a reload picks up where you left off. This is a real recording of that page, not a mockup: +**Try the barrier yourself, live: [joltrinhq.com/agents](https://joltrinhq.com/agents/).** GitHub Pages can't run a real MCP or A2A network server (no backend), so this page runs the actual `ai/verify` check compiled to WASM, wired to buttons instead of protocol calls, the same logic those servers call before committing a step. Click "Drop Prod DB" first and watch it block; the trace persists to OPFS, so a reload picks up where you left off. This is a real recording of that page, not a mockup:

Real browser recording of the live agent verification barrier demo: dropping the database is blocked until backup and validation steps actually commit, then the same drop is allowed @@ -364,7 +364,7 @@ To be completely clear on architectural boundaries: ## ๐ŸŽฎ See Joltrin in Action (Joltrin Arena Simulation) -In **[Joltrin Arena](https://sharedcode.github.io/joltrin/arena/)**, every control maps directly to a real distributed systems concept: +In **[Joltrin Arena](https://joltrinhq.com/arena/)**, every control maps directly to a real distributed systems concept: | Simulation Control | Distributed Systems Concept | Joltrin Technical Mechanism | | :--- | :--- | :--- | @@ -407,7 +407,7 @@ The project is MIT-licensed with no commercial product today. The open-core prog **What Has Been Proven** - A working Go engine with ACID transactions (WAL plus two-phase commit), a custom B-Tree, and Reed-Solomon erasure coding, each with passing automated tests (18 packages carry tests in the core Go module; run them with `go test ./...`, while the two WASM-only packages build under `GOOS=js GOARCH=wasm`, see [Performance Benchmarks](#-performance-benchmarks) below for the throughput numbers). -- A real WebAssembly build of the engine running ACID transactions, vector search, and agent-memory checkpointing entirely in-browser with zero runtime network calls after initial page load ([live demo](https://sharedcode.github.io/joltrin/)). +- A real WebAssembly build of the engine running ACID transactions, vector search, and agent-memory checkpointing entirely in-browser with zero runtime network calls after initial page load ([live demo](https://joltrinhq.com/)). - Working language bindings for Go (native), Python (`sop4py`, published to PyPI), and C# (`Sop`, published to NuGet), plus Java and Rust bindings that exist in-repo with tests but are not yet published to their package registries. - CI that runs the race detector and `govulncheck` on every change, and a changelog showing multiple rounds of real dependency and CVE remediation. @@ -448,7 +448,7 @@ Concretely, that means: fewer network hops in your hot path (sub-millisecond, in ### ๐Ÿง  For AI Infrastructure Teams -**What Joltrin already provides.** Durable, transactional checkpointing for agent reasoning state: each step an agent commits is a separate, durable B-Tree write, so a killed agent process loses nothing already committed, and a successor process can resume from the last checkpoint. This is not a diagram, it runs today in the [browser demo](https://sharedcode.github.io/joltrin/) (the "AI Agent Memory" tab) and as a Go example (`go run ./examples/agent_memory`). Joltrin also provides vector similarity search over embeddings stored in the same B-Tree as structured data (`ai/memory`, `ai/vector`), and a real swarm/worker package (`ai/swarm`) with job and result stores. +**What Joltrin already provides.** Durable, transactional checkpointing for agent reasoning state: each step an agent commits is a separate, durable B-Tree write, so a killed agent process loses nothing already committed, and a successor process can resume from the last checkpoint. This is not a diagram, it runs today in the [browser demo](https://joltrinhq.com/) (the "AI Agent Memory" tab) and as a Go example (`go run ./examples/agent_memory`). Joltrin also provides vector similarity search over embeddings stored in the same B-Tree as structured data (`ai/memory`, `ai/vector`), and a real swarm/worker package (`ai/swarm`) with job and result stores. **What could be built on Joltrin, but is not shipped today.** A production multi-agent orchestration framework, a hosted durable-memory-as-a-service for agent frameworks like LangGraph or AutoGen, and distributed MapReduce-style helpers across a live agent swarm are all described as design proposals in [`ai/SWARM_DESIGN.md`](ai/SWARM_DESIGN.md) (explicitly marked "Proposal / Vision" in that file) but are not implemented and tested the way the checkpointing and vector search primitives are. Treat anything not demonstrated in the linked demo or example as a direction, not a delivered feature. diff --git a/sop-arena/README.md b/sop-arena/README.md index 1723522df..1b7735d9d 100644 --- a/sop-arena/README.md +++ b/sop-arena/README.md @@ -1,12 +1,12 @@ # Joltrin Arena - Distributed Systems Survival Simulation & Architecture Demo -[![Deploy to GitHub Pages](https://github.com/sharedcode/joltrin/actions/workflows/deploy-demo.yml/badge.svg)](https://sharedcode.github.io/joltrin/arena/) +[![Deploy to GitHub Pages](https://github.com/sharedcode/joltrin/actions/workflows/deploy-demo.yml/badge.svg)](https://joltrinhq.com/arena/) [![Go Version](https://img.shields.io/badge/Engine-Go_/_WASM-00ADD8?logo=go)](https://github.com/sharedcode/joltrin) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](../LICENSE) > **"Break the system. Watch Joltrin recover. Experience one engine for data and compute."** -[**Live Interactive Experience: sharedcode.github.io/joltrin/arena**](https://sharedcode.github.io/joltrin/arena/) +[**Live Interactive Experience: joltrinhq.com/arena**](https://joltrinhq.com/arena/) --- @@ -99,8 +99,8 @@ npm run build Joltrin Arena is not a standalone repository. It is built and deployed from inside the main `sharedcode/sop` repository by `.github/workflows/deploy-demo.yml`, which builds this app (`npm run build`) alongside the Go WASM technical demo and publishes both into one GitHub Pages site: -- Technical demo (WASM ACID transactions, vector search, agent memory): `https://sharedcode.github.io/joltrin/` -- Joltrin Arena (this app): `https://sharedcode.github.io/joltrin/arena/` +- Technical demo (WASM ACID transactions, vector search, agent memory): `https://joltrinhq.com/` +- Joltrin Arena (this app): `https://joltrinhq.com/arena/` That workflow is the only thing in the repository that deploys to GitHub Pages; `base: './'` in `vite.config.ts` is what lets this app's built assets resolve correctly from that `/arena/` subpath. diff --git a/sop-arena/src/components/MissionSuccessModal.tsx b/sop-arena/src/components/MissionSuccessModal.tsx index 2ed38e79b..e74bc06a7 100644 --- a/sop-arena/src/components/MissionSuccessModal.tsx +++ b/sop-arena/src/components/MissionSuccessModal.tsx @@ -23,7 +23,7 @@ export const MissionSuccessModal: React.FC = ({ if (!isOpen) return null; const handleCopyShare = () => { - const text = `I just survived the Joltrin Distributed Systems Disaster with a ${metrics.reliabilityScore.toFixed(1)}% reliability score and 0 dropped writes! Try it: https://sharedcode.github.io/joltrin/arena/`; + const text = `I just survived the Joltrin Distributed Systems Disaster with a ${metrics.reliabilityScore.toFixed(1)}% reliability score and 0 dropped writes! Try it: https://joltrinhq.com/arena/`; navigator.clipboard.writeText(text).then(() => { alert('Challenge link copied to clipboard!'); }); From 51eba53bb2e73d56cacd98a68f92402740c65d98 Mon Sep 17 00:00:00 2001 From: Gerard Louis Recinto Date: Tue, 29 Sep 2026 01:44:20 -0700 Subject: [PATCH 2/4] added: joltrinhq.com link at the top of the readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f1166ea09..41a48dff3 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ ### From milliseconds to microseconds: durable memory and verification infrastructure for AI agents. +

+ ๐ŸŒ joltrinhq.com +

+

โšก Verified by benchmark: <0.3ms latency & ~6.8ยตs B-Tree operations โ†’

From edec0677e5f032bd6273c5050bb09e39d94163fe Mon Sep 17 00:00:00 2001 From: Gerard Louis Recinto Date: Thu, 1 Oct 2026 00:44:02 -0700 Subject: [PATCH 3/4] harden stripe billing, slim the readme and homepage, bump to 5.8.0 --- .github/workflows/deploy-azure.yml | 9 + CHANGELOG.md | 37 + README.md | 778 ++------------ VERSION | 2 +- bindings/csharp/Sop.CLI/Sop.CLI.csproj | 2 +- .../Sop.HttpServer/Sop.HttpServer.csproj | 2 +- bindings/csharp/Sop/Sop.csproj | 2 +- bindings/csharp/VERSION | 2 +- bindings/java/pom.xml | 2 +- bindings/python/README.md | 2 +- bindings/python/pyproject.toml | 2 +- bindings/python/sop/__init__.py | 2 +- bindings/rust/Cargo.toml | 2 +- demo-agents/index.html | 10 +- demo/CNAME | 2 +- demo/index.html | 952 +++--------------- docs/AGENT_PROTOCOLS.md | 119 +++ docs/BENCHMARKS.md | 61 ++ docs/EXAMPLES.md | 89 ++ docs/INVESTORS.md | 50 + docs/LIVE_DEMOS.md | 34 + docs/MONETIZATION_AND_TIERS.md | 21 +- docs/PACKAGES.md | 69 ++ docs/ROADMAP.md | 17 + docs/STRATEGIC_ARCHITECTURE_AND_MOAT.md | 4 +- docs/WHO_IS_IT_FOR.md | 52 + docs/WHY_JOLTRIN.md | 109 ++ governance/billing.go | 121 ++- governance/billing_readiness_test.go | 209 ++++ infra/azure/README.md | 25 + infra/azure/main.bicep | 16 +- infra/azure/main.parameters.json | 9 + infra/azure/modules/container-app.bicep | 32 +- infra/azure/modules/key-vault.bicep | 4 +- scripts/build-site.sh | 2 +- sop-arena/index.html | 10 +- tests/homepage.spec.ts | 73 ++ tools/httpserver/billing_handler.go | 101 +- tools/httpserver/billing_handler_test.go | 128 +++ 39 files changed, 1584 insertions(+), 1579 deletions(-) create mode 100644 docs/AGENT_PROTOCOLS.md create mode 100644 docs/BENCHMARKS.md create mode 100644 docs/EXAMPLES.md create mode 100644 docs/INVESTORS.md create mode 100644 docs/LIVE_DEMOS.md create mode 100644 docs/PACKAGES.md create mode 100644 docs/ROADMAP.md create mode 100644 docs/WHO_IS_IT_FOR.md create mode 100644 docs/WHY_JOLTRIN.md create mode 100644 governance/billing_readiness_test.go create mode 100644 tests/homepage.spec.ts diff --git a/.github/workflows/deploy-azure.yml b/.github/workflows/deploy-azure.yml index 15301896d..cce338ad2 100644 --- a/.github/workflows/deploy-azure.yml +++ b/.github/workflows/deploy-azure.yml @@ -14,6 +14,11 @@ # AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID # And these as repository secrets: # STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, ALERT_EMAIL +# Optional repository variables (identifiers, not secrets). While a value is +# empty the matching feature stays off: no Pro price means no Pro checkout, +# no Enterprise price means Enterprise stays contact-sales. +# STRIPE_PUBLISHABLE_KEY, STRIPE_PRO_PRICE_ID, STRIPE_ENTERPRISE_PRICE_ID, +# JOLTRIN_PUBLIC_URL # # Flow: deploy the Bicep stack first (it has a public placeholder default for # containerImage, so it stands up the ACR/Key Vault/environment/Container App @@ -75,6 +80,10 @@ jobs: -p alertEmail="${{ secrets.ALERT_EMAIL }}" \ -p stripeSecretKey="${{ secrets.STRIPE_SECRET_KEY }}" \ -p stripeWebhookSecret="${{ secrets.STRIPE_WEBHOOK_SECRET }}" \ + -p stripePublishableKey="${{ vars.STRIPE_PUBLISHABLE_KEY }}" \ + -p stripeProPriceId="${{ vars.STRIPE_PRO_PRICE_ID }}" \ + -p stripeEnterprisePriceId="${{ vars.STRIPE_ENTERPRISE_PRICE_ID }}" \ + -p publicBaseUrl="${{ vars.JOLTRIN_PUBLIC_URL }}" \ -o json > deploy-output.json acr_login_server=$(jq -r '.properties.outputs.acrLoginServer.value' deploy-output.json) echo "acrLoginServer=${acr_login_server}" >> "$GITHUB_OUTPUT" diff --git a/CHANGELOG.md b/CHANGELOG.md index e20510366..31ddbbd7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # Changelog +## v5.8.0 + +### Billing +- `GET /api/billing/plan` now returns a `checkout` block that says whether Pro and Enterprise can be bought and which environment variables are missing. It lists variable names only, never values, so an operator can see why checkout is off without reading logs. The same check is available as `governance.AssessBilling`. +- Live mode (a Stripe secret key is set) now refuses every webhook until `STRIPE_WEBHOOK_SECRET` is configured. Before, a live server with no signing secret skipped signature verification and would accept a forged `checkout.session.completed`. The public webhook route also returns 503 when no signing secret exists at all. +- `/api/billing/checkout/simulate` returns 404 unless the server is in simulation mode. With live keys it was an unauthenticated way to grant a paid tier. +- Pro checkout is refused in live mode until a real Pro price ID, a webhook secret, and absolute success and cancel URLs are all present, instead of failing at Stripe with a placeholder price. +- Enterprise stays contact-sales unless a real `STRIPE_ENTERPRISE_PRICE_ID` is configured. The checkout endpoint answers 409 for it. +- Added `JOLTRIN_PUBLIC_URL` to build the absolute Stripe return URLs. The fallback return URLs now use `joltrinhq.com` instead of `joltrin.com`. +- Tests added for missing configuration, simulation mode, invalid and missing webhook signatures, duplicate events (including after a restart), and the payment failed, recovered, canceled, and deleted subscription lifecycle. + +### Azure +- The Bicep stack takes `stripeProPriceId`, `stripeEnterprisePriceId`, and `publicBaseUrl` and passes them to the Container App as plain environment variables. Secrets still go through Key Vault references. All Stripe values default to empty, and an empty secret is stored as `unset` and treated as empty by the server, so an unconfigured deployment stays in simulation mode. +- `deploy-azure.yml` passes the new values from repository variables. Set the two Stripe secrets in GitHub rather than directly in Key Vault, because each deploy re-applies them from the workflow inputs. + +### Docs and README +- The README is now a single screen of positioning, one quickstart, the strongest verified numbers, install commands, and links. The longer material moved to `docs/`: `BENCHMARKS.md`, `LIVE_DEMOS.md`, `AGENT_PROTOCOLS.md`, `WHY_JOLTRIN.md`, `WHO_IS_IT_FOR.md`, `INVESTORS.md`, `ROADMAP.md`, `EXAMPLES.md`, and `PACKAGES.md`. +- `docs/MONETIZATION_AND_TIERS.md` documents the Stripe environment variables and the new readiness block. `infra/azure/README.md` documents which Stripe values are secret. + +### Website +- Shortened the homepage: a plain hero with one primary action, the three live experiences right below it, and a single open-core pricing section. Removed the investor-style business model, why-now, personas, value stack, and enterprise essay sections. +- Pro is now "Request Pro" with an email fallback on the static site. Removed the Apple Pay, Google Pay, instant provisioning, registry access, and annual price claims that the site could not back up. +- Canonical, Open Graph, and Twitter URLs, and `demo/CNAME`, now use `joltrinhq.com`. +- Hid the engine status pill below very wide screens so the header no longer wraps, and removed the stale "v1.0" badge. +- Added `tests/homepage.spec.ts` covering the hero, the live experience links, pricing wording, the Pro request fallback, metadata, and horizontal overflow. + +### Maintenance since v5.7.0 +- Fixed the deep sleep scheduler goroutine leak and a discarded `tx.Commit` error in the sleep cycle (#407). +- The A2A agent card now sets its protocol version (#408). +- Added a CI check that `go get` with no version resolves to the latest tag (#405) and fixed the Windows `fs` exclusion after the `/v5` rename (#404). +- Added the Cmd+K command palette to all three demo sites (#406). +- Bumped `jackson-databind` to 2.21.7 and gated merges on a per-commit Gemini Review status (#409). +- Fixed the codecov badge and stale SOP-era names in the README (#410). + +### Versioning +- All bindings (Python, Rust, Java, C#) and the server `VERSION` are aligned at 5.8.0 through `scripts/update_version.sh`. They had stayed at 5.6.0 through the v5.7.0 tag. + ## v5.7.0 ### Breaking: Module Path diff --git a/README.md b/README.md index 0d468ad0d..2ba2245a9 100644 --- a/README.md +++ b/README.md @@ -1,766 +1,110 @@
-# โšก Joltrin โšก +Joltrin logo -### From milliseconds to microseconds: durable memory and verification infrastructure for AI agents. +# Joltrin -

- ๐ŸŒ joltrinhq.com -

- -

- โšก Verified by benchmark: <0.3ms latency & ~6.8ยตs B-Tree operations โ†’ -

+**Durable memory and a verification barrier for AI agents, in one embedded Go library.** -

- Joltrin logo -

+[joltrinhq.com](https://joltrinhq.com/) ยท [Technical demo](https://joltrinhq.com/) ยท [Arena](https://joltrinhq.com/arena/) ยท [Agent barrier](https://joltrinhq.com/agents/) -[![Discussions](https://img.shields.io/github/discussions/SharedCode/joltrin)](https://github.com/SharedCode/joltrin/discussions) [![CI](https://github.com/SharedCode/joltrin/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/SharedCode/joltrin/actions/workflows/ci.yml) [![Go Tests](https://github.com/SharedCode/joltrin/actions/workflows/go.yml/badge.svg?event=push&branch=master)](https://github.com/SharedCode/joltrin/actions/workflows/go.yml) -[![Release](https://img.shields.io/github/v/release/SharedCode/joltrin)](https://github.com/SharedCode/joltrin/releases) [![codecov](https://codecov.io/gh/SharedCode/sop/branch/master/graph/badge.svg)](https://app.codecov.io/github/SharedCode/sop) +[![Release](https://img.shields.io/github/v/release/SharedCode/joltrin)](https://github.com/SharedCode/joltrin/releases) [![Go Reference](https://pkg.go.dev/badge/github.com/sharedcode/joltrin/v5.svg)](https://pkg.go.dev/github.com/sharedcode/joltrin/v5) -[![Go version](https://img.shields.io/github/go-mod/go-version/SharedCode/joltrin)](go.mod) [![License](https://img.shields.io/github/license/SharedCode/joltrin)](LICENSE) -[![Live Demos](https://img.shields.io/badge/Live_Demos-GitHub_Pages-10B981?logo=github)](https://joltrinhq.com/arena/) -[![MCP](https://img.shields.io/badge/MCP-tools%2Fmcpserver-4A4A4A)](docs/MCP_A2A_AND_VERIFICATION_ENGINE.md) -[![A2A](https://img.shields.io/badge/A2A-tools%2Fa2aagent-4A4A4A)](docs/MCP_A2A_AND_VERIFICATION_ENGINE.md)
-**Joltrin** (formerly SOP, Scalable Objects Persistence) is a unified in-process state engine providing transactional persistence, durable agent memory, distributed storage primitives, explicit-state verification, and WebAssembly persistence. It combines a sector-aligned **copy-on-write B-Tree**, **checkpointed episodic agent memory**, **vector similarity search**, and a **deterministic safety verification barrier** for MCP and A2A runbooks into one library. - -Instead of managing separate vector databases, message brokers, caching tiers, distributed lock managers, and fragile external checkpoint stores, Joltrin lets your AI agents maintain crash-resilient memory and enforce operational invariants directly within the execution boundary. +Joltrin (formerly SOP) is an ACID-compliant B-Tree storage engine that runs inside your process. For AI agents it provides three things in one library: memory that survives a crash and can be resumed by another worker, vector search stored next to structured data in the same transaction, and a verification barrier that blocks a risky action until its preconditions are proven. -> **Why "from milliseconds to microseconds"?** Traditional multi-tier architectures incur an estimated 15-50ms network round-trip penalty across external services (Redis, message queues, relational databases). Joltrin runs embedded in-process, shifting latency from milliseconds to microseconds: empirical benchmarks measure **<0.3ms** end-to-end in-process execution, **~6.87ยตs** per B-Tree write (>145,000 ops/sec), and **~6.95ยตs** per read (>143,000 ops/sec) with full ACID consistency. -> ๐Ÿ”— **Proof & Benchmark Reference:** [View Detailed Benchmarks & Microsecond Breakdown โ†’](#-performance-benchmarks) ยท Benchmark suite: [`tools/benchmark`](tools/benchmark) ยท Live client-side run: [Technical WASM Demo](https://joltrinhq.com/) +**Who it is for.** Engineers building agent systems, edge or local-first apps, and teams running Redis, a queue, and Postgres only to keep one application's state durable. -

- Live Joltrin demo: in-process ACID transactions, distributed Arena simulation, and deterministic AI agent verification barrier -

+**Why it matters.** An agent that can call tools needs more than a good prompt. It needs state that survives a failure and a check that runs before the action, not after. Joltrin puts both in the same process and the same transaction boundary, so there is no network hop and no separate service to operate.

- ๐Ÿง  Launch Technical Demo โ†’   |   - ๐ŸŽฎ Play Joltrin Arena โ†’   |   - ๐Ÿ”Œ Launch Agent Barrier โ†’ + Joltrin demo: in-process ACID transactions, the Arena simulation, and the agent verification barrier

-| Experience | Description | Live Interactive Link | -| :--- | :--- | :--- | -| ๐Ÿง  **Joltrin Technical Demo** | **Client-Side Zero-Server WebAssembly Engine**
Execute live ACID transactions, 128-dimensional vector cosine searches, microsecond benchmarks, and durable AI agent memory checkpoints (kill the agent mid-task, watch a successor resume from the B-Tree) running 100% in your browser with **0 runtime HTTP network calls after initial load**. | [**Launch Technical Demo โ†’**](https://joltrinhq.com/) | -| ๐ŸŽฎ **Joltrin Arena** | **Distributed Systems Survival Simulation**
Command a live digital cluster. Scale worker swarms, crash storage nodes, trigger transaction storms, and watch Joltrin automatically redistribute tasks and rebuild parity in real-time. | [**Play Joltrin Arena โ†’**](https://joltrinhq.com/arena/) | -| ๐Ÿ”Œ **Joltrin Agent Verification Barrier** | **The MCP/A2A Safety Check, Clickable**
The same `ai/verify` barrier gating `tools/mcpserver` and `tools/a2aagent`, compiled to WASM. Try dropping a database before validating a backup and watch it get blocked, in your browser, with the trace persisted to OPFS. | [**Launch Agent Barrier โ†’**](https://joltrinhq.com/agents/) | - ---- - -## โšก Try It in 30 Seconds - -Clone the repository and run the unified interactive demo: - -```bash -git clone https://github.com/sharedcode/joltrin.git && cd joltrin && ./scripts/demo.sh -``` - -The interactive script lets you execute and verify each workflow shown on this page: -1. **Verification Barrier**: Safety precedence check gating destructive operations (`examples/verify_barrier`). -2. **AI Agent Memory**: B-Tree reasoning checkpoints with mid-task worker failure and sub-15ms recovery (`examples/agent_memory`). -3. **Core Test Suite**: Sanity check running core storage, filesystem, and server unit tests. -4. **Local Protocol Probe**: JSON-RPC over stdio (`cmd/sop-mcp-server`) and live A2A agent-card probe (`cmd/sop-a2a-agent`). - -You can also run any step directly with flags: -```bash -./scripts/demo.sh --barrier # Option 1: Precedence barrier check -./scripts/demo.sh --memory # Option 2: AI agent memory failover -./scripts/demo.sh --test # Option 3: Core engine test suite -./scripts/demo.sh --protocol # Option 4: Local MCP and A2A reachability probe -./scripts/demo.sh --all # Run all 4 stages sequentially -``` - -Prefer raw Go commands without scripts? Run them directly: -```bash -go run ./examples/verify_barrier # Option 1 -go run ./examples/agent_memory # Option 2 -go test ./... # Option 3 -``` - -No local Go toolchain? Run the exact same demo suite inside Docker: -```bash -# Run the interactive demo suite via Docker -docker run --rm -it -v "$PWD":/src -w /src golang:1.26-alpine ./scripts/demo.sh - -# Or run the published quickstart container from GHCR -docker run --rm ghcr.io/sharedcode/joltrin-quickstart -``` - -### ๐Ÿ“‰ Engineering ROI, Verified in This Repo - -No revenue or customer numbers exist yet for this project (see [For Investors](#-for-investors) for the honest version of that). What is verified today, in this repo, is the infrastructure cost this architecture removes: - -| What collapses | From | To | -| :--- | :--- | :--- | -| **Network hops per operation** | 3 hops across Redis, a queue, and Postgres/Cassandra (estimated 15-50ms network round-trip overhead) | 1 embedded in-process call (<0.3ms measured latency, >145k ops/sec) | -| **Stateful services to operate, patch, and page on** | Redis + Kafka/RabbitMQ + Postgres/Cassandra + ZooKeeper (4+) | 1 embedded library | -| **Language surfaces shipped** | N/A | Go (native), Python (`sop4py` on PyPI), C# (`Sop` on NuGet); Java and Rust bindings exist in-repo with tests, not yet published | -| **CI rigor on every change** | N/A | `govulncheck` clean on every push; race detector on the core engine packages (`btree`, `common`, `fs`, `inmemory`); 3-OS build and test matrix (Linux, macOS, Windows) | -| **Deployment footprint of the technical demo** | A server-backed demo stack | WASM build running ACID transactions, vector search, and agent-memory checkpointing 100% client-side, 0 runtime HTTP calls after page load ([live](https://joltrinhq.com/)) | - -Every row above is something you can run yourself, not a projection. See [Performance Benchmarks](#-performance-benchmarks) for the throughput numbers behind the latency claim, and [What Has Not Yet Been Proven](#-for-investors) for what this table deliberately leaves out. - ---- - -## ๐Ÿš€ Experience Joltrin - -You can test Joltrin directly in your browser without installing anything via the live interactive experiences above ([Technical Demo](https://joltrinhq.com/), [Joltrin Arena](https://joltrinhq.com/arena/), and [Agent Verification Barrier](https://joltrinhq.com/agents/)). The technical demo demonstrates the engine's core power directly: safe, ACID-transactional storage running on web storage itself (OPFS), with zero server and zero network calls after the initial page loads the WASM binary. Everything else on this page, including the agent verification barrier below, is built on top of that same engine, a reference implementation showing one concrete use case. - -The technical demo persists across reloads now, to Origin Private File System, via the browser's async File System Access API. The diagram below is the real tradeoff behind that choice, not a benchmark; no throughput numbers are shown because none have been measured for either path in this repo. - -

- OPFS persistence: the async File System Access API path this repo built, versus the synchronous createSyncAccessHandle path that would require moving the WASM binary into a dedicated Worker, deliberately not built this pass -

- -That same WASM-compiled engine is what the Agent Verification Barrier row above actually runs on, not a separate reimplementation: it's the concrete reference implementation this repo ships to answer "what do you actually build with a durable, transactional engine running client-side?" It is an AI agent safety check an agent cannot talk its way around, with the trace itself durable in OPFS across reloads. The next section is that barrier in depth, plus the same check reachable server-side over MCP and A2A. - ---- - -## ๐Ÿ”Œ Agent Protocols: MCP, A2A, and a Real Verification Barrier - -Joltrin runbooks are reachable from two agent protocols, [Model Context Protocol](https://modelcontextprotocol.io/) and [Agent2Agent](https://a2a-protocol.org/), both gated by the same safety-and-reachability check before a step is allowed to commit. Real, tested code (`ai/verify`, `tools/mcpserver`, `tools/a2aagent`), not a diagram of an idea; see [MCP, A2A, and the Verification Engine](docs/MCP_A2A_AND_VERIFICATION_ENGINE.md) for the full audit and design writeup. - -

- An MCP client and an A2A orchestrator each reach a separate protocol server, both backed by the same tools/runbookstore.Store and gated by the same ai/verify safety check before a step commits -

- -**Try the barrier yourself, live: [joltrinhq.com/agents](https://joltrinhq.com/agents/).** GitHub Pages can't run a real MCP or A2A network server (no backend), so this page runs the actual `ai/verify` check compiled to WASM, wired to buttons instead of protocol calls, the same logic those servers call before committing a step. Click "Drop Prod DB" first and watch it block; the trace persists to OPFS, so a reload picks up where you left off. This is a real recording of that page, not a mockup: - -

- Real browser recording of the live agent verification barrier demo: dropping the database is blocked until backup and validation steps actually commit, then the same drop is allowed -

- -The same scenario also runs as a terminal program, `examples/verify_barrier`, and the servers themselves are one command away: - -

- Real terminal recording of ai/verify blocking a database drop until a backup is validated, then allowing it once the precondition is actually met -

- -```bash -# Run the barrier demo yourself -go run ./examples/verify_barrier - -# Serve the same runbook over MCP (stdio) -# Note: this speaks JSON-RPC over stdin/stdout for an MCP client (Claude -# Desktop, an SDK, etc). Run bare in a terminal, it'll print "Parse error" -# for every line you type, since your keystrokes aren't valid JSON-RPC - -# that's expected, not a bug. Point an MCP client at this command instead. -go run ./cmd/sop-mcp-server - -# Serve it over A2A instead, then fetch its agent card -go run ./cmd/sop-a2a-agent & -curl localhost:8087/.well-known/agent-card.json - -# Claude has no native A2A client, so bridge the two: sop-a2a-bridge -# resolves the agent card above and re-exposes execute_step as an MCP tool -go run ./cmd/sop-a2a-bridge -agent-url http://localhost:8087 -``` - -### Wiring `sop-mcp-server` into Claude - -`cmd/sop-mcp-server` speaks JSON-RPC over stdio and evaluates the barrier policies below (`ai/verify`'s `CheckSafety`) before `execute_step` is allowed to commit; a blocked step comes back as `input-required`, not a crash. Point either Claude client at the command: - -**Claude Desktop** (`claude_desktop_config.json`, stdio transport): - -```json -{ - "mcpServers": { - "joltrin": { - "command": "go", - "args": ["run", "./cmd/sop-mcp-server"], - "cwd": "/absolute/path/to/joltrin" - } - } -} -``` - -Swap `"command"/"args"` for a prebuilt binary once you've run `go build -o sop-mcp-server ./cmd/sop-mcp-server`: - -```json -{ - "mcpServers": { - "joltrin": { - "command": "/absolute/path/to/joltrin/sop-mcp-server" - } - } -} -``` - -**Claude Code** (CLI): - -```bash -claude mcp add --transport stdio joltrin -- go run ./cmd/sop-mcp-server -``` - -### Wiring `sop-a2a-agent` into Claude (via `sop-a2a-bridge`) - -Claude doesn't speak A2A natively, MCP is the protocol its clients actually implement, so reaching an A2A agent means bridging the two, not writing an A2A client into Claude itself. `tools/a2abridge` is that bridge: an MCP server that resolves a running `sop-a2a-agent`'s card and re-exposes its `execute_step` skill as an MCP tool of the same name, translating each call into a real A2A task delegation over the wire and translating the resulting task state (`completed` / `input-required` / `failed`) back into an MCP tool result. It's built on the official `a2aclient` SDK package, not a hand-rolled JSON-RPC client, and it's covered by its own integration tests (`tools/a2abridge/bridge_test.go`) that drive the full MCP -> bridge -> real A2A wire protocol -> executor round trip, including the blocked, allowed, and remote-failure paths. - -Start the agent, then point the bridge at it: - -```bash -go run ./cmd/sop-a2a-agent & -go run ./cmd/sop-a2a-bridge -agent-url http://localhost:8087 -``` - -**Claude Desktop:** - -```json -{ - "mcpServers": { - "joltrin-a2a": { - "command": "go", - "args": ["run", "./cmd/sop-a2a-bridge", "-agent-url", "http://localhost:8087"], - "cwd": "/absolute/path/to/joltrin" - } - } -} -``` - -**Claude Code** (CLI): - -```bash -claude mcp add --transport stdio joltrin-a2a -- go run ./cmd/sop-a2a-bridge -agent-url http://localhost:8087 -``` - -### Barrier policies `ai/verify` enforces - -`ai/verify` is a general-purpose explicit-state precondition/postcondition graph (`Step`, `SafetyRule`, `ReachabilityRule` in `ai/verify/verify.go`) with no built-in notion of databases, clusters, or money. Every state is an opaque string, so a barrier policy for any category of risky action is defined the same way: name the states that must hold, name the step that establishes the dangerous one, and let `CheckSafety` gate it. This repo ships three concrete runbooks in `tools/runbookstore` built on that same generic mechanism, one per risky-action category, plus the generic out-of-order rejection that applies to all of them: - -- **Destructive operations** (`DBMaintenanceWorkflow`, e.g. dropping a database): `drop_prod_db` requires `backup_validated`, which only `validate_backup` establishes after `take_backup`. A `SafetyRule` (`no-drop-without-validated-backup`) names the barrier explicitly, and a `ReachabilityRule` guarantees `rollback_complete` stays reachable even after the drop. -- **Resource & topology mutations** (`ClusterTopologyWorkflow`, e.g. draining a node, failing over a cluster): `drain_node` and `failover_cluster` both require `replica_parity_verified`, which requires `health_check_passed` first. Reinstating the node or cluster (`topology_rollback_complete`) stays reachable from every state in the graph, including after a worker is terminated post-drain. -- **Financial / ledger-mutating actions** (`LedgerTransferWorkflow`, e.g. balance updates, account transfers): `commit_transfer` requires `zero_sum_verified`, which only `verify_zero_sum_invariant` establishes after balances are mutated inside a `transaction_serialized` scope (`begin_serializable_transaction` -> `snapshot_balances` -> `apply_debit_credit`). Reversal (`ledger_rollback_complete`) stays reachable both before and after commit. -- **Unverified / out-of-order execution**: this is the same mechanism underlying all three, not a separate check. `CheckSafety` rejects any step whose `Requires` states haven't been established yet in the current `Trace`, and rejects any step that would establish a `Forbidden` state without its paired `Requires` state already holding. An agent (or a client bug) trying to call `drain_node` or `commit_transfer` before its preconditions land gets a named, actionable violation back, never a silent no-op. - -Only `DBMaintenanceWorkflow` is registered by the example binaries (`cmd/sop-mcp-server`, `cmd/sop-a2a-agent`) today; `ClusterTopologyWorkflow` and `LedgerTransferWorkflow` are available in `tools/runbookstore` (with tests in `tools/runbookstore/examples_test.go`) as worked examples of modeling the other two categories on the same engine. Register them with `store.RegisterWorkflow` in your own server to serve them. - -What this checker is, precisely, matters more than what it sounds like it might be: explicit-state safety and reachability checking over a finite workflow graph, the "P is preceded by Q" precedence pattern from Dwyer/Avrunin/Corbett's property specification patterns (ICSE 1999), not general-purpose LTL/CTL model checking. No formula parser, no Bรผchi automata, no neural component translating natural language into the graph today. The full accounting of what's built versus proposed is in the linked doc, not summarized rosily here. - ---- - -## ๐Ÿ’ก What Problem Does Joltrin Solve? - -Most distributed applications require two fundamentally different operations: -1. **Storing state reliably** (databases, key-value stores, vector indexes) -2. **Coordinating work across machines** (task queues, locks, retries, worker failovers) - -Today, developers solve this by assembling a multi-component infrastructure stack: - -``` -THE FRAGMENTED MULTI-COMPONENT STACK (Without Joltrin): - -[ Application ] - โ”‚ - โ”œโ”€โ”€โ–บ (TCP Hop 1: 5-15ms) โ”€โ”€โ–บ Redis (Distributed Locks & Leases) - โ”œโ”€โ”€โ–บ (TCP Hop 2: 5-15ms) โ”€โ”€โ–บ RabbitMQ / Kafka (Task Queue) - โ”œโ”€โ”€โ–บ (TCP Hop 3: 10-30ms) โ”€โ”€โ–บ PostgreSQL / Cassandra (Persistent Storage) - โ””โ”€โ”€โ–บ (Failover Glue) โ”€โ”€โ–บ ZooKeeper / Custom Retry & Outbox Daemons - -โš ๏ธ 4 infrastructure boundaries | Estimated 15-50ms network latency tax | High split-brain failure risk | High maintenance overhead -``` - -When an application worker crashes between releasing a lock in Redis and committing to PostgreSQL, state can enter an inconsistent split-brain condition. Engineering teams end up spending substantial time writing and maintaining outbox listeners, lock renewers, and compensating retry logic. - ---- - -## โšก Why Joltrin? - -Joltrin takes a different approach: **co-locate storage and compute inside the same engine boundary.** - -``` -THE UNIFIED DATA & COMPUTE PLATFORM (With Joltrin): - -[ Application ] - โ”‚ - โ””โ”€โ”€โ–บ (Embedded In-Process Call: < 0.3ms latency) - โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚ JOLTRIN ENGINE โ”‚ - โ”‚ โ€ข Persistent B-Tree Storage (Sector-aligned Direct I/O) โ”‚ - โ”‚ โ€ข Strict Serializable ACID Transactions (WAL + 2PC) โ”‚ - โ”‚ โ€ข Swarm Compute & Autonomous Task Redistribution โ”‚ - โ”‚ โ€ข High-Dimensional Vector Similarity Indexing (SIMD) โ”‚ - โ”‚ โ€ข Reed-Solomon Erasure Coding & Partition Resilience โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - -โœ“ 1 Single Engine | Sub-millisecond execution | 100% ACID consistency | Automated failover -``` - -Because compute workers, task queues, and storage partitions share the same transaction boundary, a worker failure triggers an automatic rollback of uncommitted work and re-assigns the task in milliseconds with zero orphan locks. - ---- - -## โฑ๏ธ Why Now? - -Three industry shifts make this architecture increasingly relevant: - -1. **The Explosion of Autonomous AI Agents**: Multi-agent swarms require frequent context checkpointing, vector similarity searches, and task coordination. Assembling this across Postgres, Pinecone, Redis, and Celery creates high failure surface area. -2. **Edge and Local-First Computing**: Devices in factory automation, vehicles, and retail branches cannot rely on constant connections to central cloud databases. They need full ACID storage and local coordination that works offline. -3. **Infrastructure Simplification**: Engineering organizations are seeking to reduce the operational overhead and cloud bills associated with running dozens of discrete microservices just to manage state and queues. - ---- - -## ๐Ÿ” What Makes Joltrin Different? - -Joltrin is built on five core technical principles: - -1. **Embedded Storage Engine**: Operates in-process in Go, Python, and C#, eliminating TCP network hops for local reads and writes. -2. **ACID Transactions without Database Servers**: Implements Write-Ahead Logging (WAL) and Two-Phase Commit (2PC) with copy-on-write page isolation. -3. **Swarm Compute Coordination**: Workers coordinate task execution using storage-anchored sector claims and heartbeat leases without requiring global consensus bottlenecks (like Paxos or Raft) on the hot path. -4. **Reed-Solomon Erasure Coding**: Protects storage shards from hardware failure by striping parity blocks across drives rather than paying the 3x disk storage cost of full replication. -5. **Integrated Vector & Structured Storage**: Stores high-dimensional vector embeddings in the same B-Tree segments as structured metadata, allowing single-transaction memory commits. - ---- - -## โš–๏ธ Joltrin vs. Alternatives - -Every architecture involves tradeoffs. Here is an honest comparison of where Joltrin fits relative to industry standards: - -| Capability | PostgreSQL | Redis | Kafka | Temporal | Pinecone | SQLite | Joltrin | -| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | -| **ACID Transactions** | โœ“ | โ–ณ | โœ— | โœ— | โœ— | โœ“ | โœ“ | -| **Ordered B-Tree Range Scans** | โœ“ | โ–ณ | โœ— | โœ— | โœ— | โœ“ | โœ“ | -| **Embedded In-Process** | โœ— | โœ— | โœ— | โœ— | โœ— | โœ“ | โœ“ | -| **Swarm Work Coordination** | โœ— | โ–ณ | โ–ณ | โœ“ | โœ— | โœ— | โœ“ | -| **Vector Similarity Search** | โ–ณ (pgvector) | โ–ณ | โœ— | โœ— | โœ“ | โœ— | โœ“ | -| **Erasure Coding (N+K)** | โœ— | โœ— | โœ— | โœ— | โœ— | โœ— | โœ“ | -| **Zero Standalone Daemons** | โœ— | โœ— | โœ— | โœ— | โœ— | โœ“ | โœ“ | - -*Legend: `โœ“` First-class native capability | `โ–ณ` Partial or requires plugin/extension | `โœ—` Not designed for this capability* - -### Detailed Tradeoffs by Competitor: - -- **PostgreSQL**: Industry standard for general relational databases. Choose Postgres when you need complex relational schemas, advanced SQL aggregations, or standard ecosystem tooling. Joltrin is better suited when you want an embedded storage engine inside your application process without database server management. -- **Redis**: Industry standard for ultra-low-latency in-memory key-value caching. Choose Redis when all data fits in RAM and you need simple cache operations. Joltrin provides durable B-Tree disk persistence, multi-item ACID transactions, and erasure coding. -- **Kafka / RabbitMQ**: Industry standards for high-volume streaming and pub/sub. Choose Kafka when you need multi-datacenter event streams and log retention. Joltrin provides transactional task queues co-located with storage state for local swarms. -- **NATS (optional, `adapters/nats`)**: not a replacement for anything joltrin embeds, and not on the hot path. If a team already runs NATS as part of their own architecture, `adapters/nats.VerifyBridge` will publish `ai/verify` barrier decisions to it, fire-and-forget, after the decision is already made, so another service outside joltrin's process can observe it without polling. Nothing imports this by default and a publish failure can never change the barrier's own answer. See the addendum in `docs/MCP_A2A_AND_VERIFICATION_ENGINE.md` for the full reasoning on why this doesn't reverse the embedded design. -- **Temporal**: Industry standard for long-running durable workflows spanning external microservices. Choose Temporal for multi-week human-in-the-loop workflows across disparate clouds. Joltrin is designed for local-to-cluster co-located data and task execution. -- **SQLite**: Industry standard for embedded single-file relational databases. Choose SQLite for client desktop/mobile apps needing SQL. Joltrin is designed for high-concurrency multi-threaded workers, clustered coordination, partitioned vector stores, and erasure coding. - ---- - -## ๐ŸŽฏ When Joltrin Is a Great Fit - -- **AI Agent Memory & Swarm Workforces**: Autonomous agents requiring durable conversation memory, vector similarity search, and task hand-offs without fragmented external databases. Checkpoints commit directly to B-Tree segments with atomic rollback if a worker crashes mid-reasoning. -- **Real-Time Systems & Simulation State**: Game servers, robotics, and spatial computing needing sub-millisecond in-process transactional serialization (measured at 100k-145k ops/sec in local benchmarks) without database network hops. -- **Financial & Escrow Ledgers**: Systems requiring snapshot isolation, optimistic concurrency control (OCC), two-phase commit (2PC), and invariant verification (such as validating zero-sum account deltas before commit). -- **Edge & IoT Computing**: Devices operating in local or intermittent network environments that need local embedded ACID persistence, with experimental peer coordination. -- **Serverless Workloads**: Cloud functions and containers that need durable storage without exhausting external database connection pools. - ---- - -## ๐Ÿšซ When Joltrin is NOT the Right Tool - -To be completely clear on architectural boundaries: - -- **Massive Analytical Warehousing**: If you are running multi-petabyte columnar analytics across billions of historical events, specialized OLAP warehouses (like ClickHouse or Snowflake) are the right choice. -- **Global Multi-Region Consensus**: If your application requires synchronous commits across continents with multi-region Raft/Paxos quorums, dedicated distributed SQL databases (like CockroachDB or Google Spanner) are designed for that problem. -- **Simple Stateless CRUD Apps**: If your application is a standard CRUD dashboard with low traffic, standard PostgreSQL or MySQL with an ORM is simpler and has more ecosystem plugins. - ---- - -## ๐ŸŽฎ See Joltrin in Action (Joltrin Arena Simulation) - -In **[Joltrin Arena](https://joltrinhq.com/arena/)**, every control maps directly to a real distributed systems concept: - -| Simulation Control | Distributed Systems Concept | Joltrin Technical Mechanism | -| :--- | :--- | :--- | -| **Add Worker** | Swarm Compute | Dynamic queue rebalancing across peer worker nodes without central master bottlenecks. | -| **Remove Worker** | Graceful Degradation | Active tasks drained and re-assigned to healthy nodes with zero dropped writes. | -| **Kill Node / Storage Fault** | Fault Tolerance | **Reed-Solomon Erasure Coding** reconstructs missing B-Tree blocks in-memory from parity chunks. | -| **Transaction Storm** | Concurrency & Isolation | **Optimistic Concurrency Control (OCC)** serializes conflicting writes in microseconds. | -| **Increase Workload (100k TPS)** | Scalability | B-Tree node segments partition write load across sector-aligned storage handles. | -| **Automatic Self-Healing** | Resilient Coordination | Heartbeat lease detection triggers automated task redistribution in `<15ms`. | - ---- - -## ๐Ÿ‘ฅ Who Joltrin Is For - -Joltrin is one codebase, but different people will care about it for different reasons. Jump to the section that matches you: - -[Investors](#-for-investors) ยท [Investment Banking & Tech Finance](#-for-investment-banking--technology-finance) ยท [Potential Customers](#-for-potential-customers) ยท [CTOs & Engineering Executives](#-for-ctos--engineering-executives) ยท [AI Infrastructure Teams](#-for-ai-infrastructure-teams) ยท [Platform, SRE & Cloud Engineers](#-for-platform-sre--cloud-engineers) ยท [Researchers & Distributed Systems Engineers](#-for-researchers--distributed-systems-engineers) ยท [Students & Learners](#-for-students--learners) ยท [Developers](#-for-developers) ยท [Engineering Leaders & Hiring Managers](#-for-engineering-leaders--hiring-managers) - -### ๐Ÿ’ฐ For Investors - -**The problem.** Teams building stateful distributed applications, agent systems especially, routinely wire together a database, a cache, a message queue, a lock manager, and a workflow engine just to get durable state and coordinated work. Each boundary between those systems is a place where consistency breaks during a partial failure. That integration tax is paid by every team that builds this kind of system, repeatedly. - -**What Joltrin uniquely combines.** A B-Tree storage engine, ACID transactions, and swarm task coordination live inside one embedded library instead of behind separate network services. That is an architectural bet, not a settled fact: it trades the maturity and ecosystem of specialized tools (Postgres, Kafka, Temporal) for fewer moving parts and a single consistency boundary. Whether that tradeoff wins in a given workload is something a team has to evaluate, which is exactly what the [comparison table](#๏ธ-joltrin-vs-alternatives) below is for. - -**Investment Thesis** -Joltrin is an open-source bet that "data plus compute in one embedded engine" is a better default for a growing category of workloads (AI agents, edge devices, real-time systems) than assembling that stack from five separate products. If that thesis is right, the project that owns the reference implementation of that architecture has a shot at becoming the default choice for it, the way SQLite became the default embedded relational store. That is a multi-year distribution bet, not a proven outcome. - -**Why Now** -- AI agent systems increasingly need durable memory, checkpointing, and multi-worker coordination, and today that is usually stitched together from a vector database, a cache, and a job queue. -- Edge and local-first computing (factory automation, vehicles, retail devices) need ACID storage that keeps working without a constant connection to a central database. -- Engineering organizations are actively trying to cut the number of discrete stateful services they operate, both for cost and for on-call load. - -These are real, observable industry trends. No specific market-sizing figures are cited here because this repository has not commissioned or verified any (see Market Opportunity below). - -**Market Opportunity** -Joltrin overlaps several existing categories rather than creating one from nothing: embedded databases (SQLite, RocksDB), distributed coordination (Zookeeper, etcd, Temporal), vector databases (Pinecone, Weaviate, pgvector), and workflow/task systems (Celery, Ray). Plausible buyers are teams building AI agent infrastructure, edge and IoT platforms, real-time/simulation backends, and fintech ledgers with strict transactional invariants. No independently sourced TAM/SAM/SOM figures are presented here; a rigorous estimate would require external market research (for example, from Gartner or IDC) that this project has not commissioned. - -**Business Model Opportunities** -The project is MIT-licensed with no commercial product today. The open-core progression and architectural foundations for commercial governance are detailed in [Monetization & Editions Architecture](#-monetization--editions-architecture) below. - -**What Has Been Proven** -- A working Go engine with ACID transactions (WAL plus two-phase commit), a custom B-Tree, and Reed-Solomon erasure coding, each with passing automated tests (23 packages carry tests in the core Go module; run them with `go test ./...`, while the two WASM-only packages build under `GOOS=js GOARCH=wasm`, see [Performance Benchmarks](#-performance-benchmarks) below for the throughput numbers). -- A real WebAssembly build of the engine running ACID transactions, vector search, and agent-memory checkpointing entirely in-browser with zero runtime network calls after initial page load ([live demo](https://joltrinhq.com/)). -- Working language bindings for Go (native), Python (`sop4py`, published to PyPI), and C# (`Sop`, published to NuGet), plus Java and Rust bindings that exist in-repo with tests but are not yet published to their package registries. -- CI that runs the race detector and `govulncheck` on every change, and a changelog showing multiple rounds of real dependency and CVE remediation. - -**What Has Not Yet Been Proven** -- No production deployments or paying customers are documented anywhere in this repository. -- No independent, third-party, or peer-reviewed benchmarks exist; the performance numbers below come from this project's own benchmark harness on a single workstation, not a controlled multi-system comparison. -- Joltrin Arena's cluster view is a UI simulation of the underlying concepts for demonstration purposes, not a live multi-node deployment; multi-node swarm clustering itself is real and tested (`examples/swarm_clustered`, `examples/swarm_standalone`), but has not been run at meaningful scale or under adversarial network conditions in public. -- No formal third-party security audit has been performed. -- No case studies, design partners, or committed customers exist yet. - -### ๐Ÿฆ For Investment Banking & Technology Finance - -**Technology category.** Joltrin sits in the embedded data infrastructure layer: a storage and coordination engine that applications link against directly, similar in category placement to SQLite or RocksDB, but extended with distributed ACID transactions and task coordination that those two do not attempt. - -**Adjacent markets.** Embedded/operational databases, distributed coordination and workflow orchestration, vector search infrastructure, and AI agent infrastructure tooling. Each of those adjacent markets has established commercial players (see the [comparison table](#๏ธ-joltrin-vs-alternatives)), which is useful context for sizing the competitive landscape Joltrin would need to differentiate against. - -**Potential strategic relevance.** This could include: infrastructure vendors looking to add an embedded, agent-friendly storage layer to an existing platform; cloud providers evaluating lightweight alternatives to running separate managed database, cache, and queue services for edge or agent workloads; or AI infrastructure companies needing a durable state layer under an agent runtime. None of this reflects any actual approach, interest, or discussion from any party; it is offered as a way to reason about where the technology could fit strategically. - -**Open-source distribution.** The project is distributed under the MIT license with no dual-licensing or commercial tier today. That maximizes adoption friction reduction (any team can use it in production immediately) at the cost of no current monetization mechanism. See [Monetization & Editions Architecture](#-monetization--editions-architecture) for the open-core progression and architectural separation. - -**Competitive landscape.** Summarized in the [Joltrin vs. Alternatives](#๏ธ-joltrin-vs-alternatives) table further down. No competitor is presented as inferior; each is a mature, widely deployed system that Joltrin would need to displace or complement for any given workload. - -### ๐Ÿข For Potential Customers - -**Is Joltrin Right For Me?** Start from the existing [When Joltrin is a Great Fit](#-when-joltrin-is-a-great-fit) and [When Joltrin is NOT the Right Tool](#-when-joltrin-is-not-the-right-tool) sections above, they are the concrete answer. As a quick filter: - -- If you are currently running Redis plus Postgres plus a queue just to get durable state and coordinated background work for one application, and that application's data fits comfortably on the machines it runs on, Joltrin is worth evaluating as a replacement for that stack. -- If you already run Postgres or Kafka at scale for reasons unrelated to this problem (complex SQL, multi-datacenter event retention, an existing team's expertise), Joltrin is more likely to complement than replace what you have. -- If your workload is petabyte-scale analytics or requires synchronous multi-region consensus, Joltrin is not the right tool today; see the section above for specifics. - -Joltrin is a library you embed, not a managed service you sign up for. There is no hosted offering today; you run it yourself, in-process, in your own infrastructure. - -### ๐Ÿ‘” For CTOs & Engineering Executives - -Every service you run that exists only to hold state or coordinate work (a cache, a queue, a lock manager) is a service your team has to patch, monitor, upgrade, and page on. Joltrin's bet is that collapsing storage, transactions, and task coordination into one embedded library reduces that surface for the workloads it fits, at the cost of giving up the specialized tooling and operational maturity of dedicated systems your team may already know well. - -Concretely, that means: fewer network hops in your hot path (sub-millisecond, in-process calls instead of 15 to 50ms across Redis, a queue, and Postgres), one dependency to patch and upgrade instead of several, and a transaction boundary that spans your data and your background work instead of stopping at the database. It also means your team takes on a less mature, less battle-tested piece of infrastructure than Postgres or Kafka, with a correspondingly smaller ecosystem, smaller hiring pool of people who already know it, and no enterprise support contract available today. Evaluate it the way you would any early infrastructure bet: pilot it on one bounded, non-critical workload before committing a core system to it. - -### ๐Ÿง  For AI Infrastructure Teams - -**What Joltrin already provides.** Durable, transactional checkpointing for agent reasoning state: each step an agent commits is a separate, durable B-Tree write, so a killed agent process loses nothing already committed, and a successor process can resume from the last checkpoint. This is not a diagram, it runs today in the [browser demo](https://joltrinhq.com/) (the "AI Agent Memory" tab) and as a Go example (`go run ./examples/agent_memory`). Joltrin also provides vector similarity search over embeddings stored in the same B-Tree as structured data (`ai/memory`, `ai/vector`), and a real swarm/worker package (`ai/swarm`) with job and result stores. - -**What could be built on Joltrin, but is not shipped today.** A production multi-agent orchestration framework, a hosted durable-memory-as-a-service for agent frameworks like LangGraph or AutoGen, and distributed MapReduce-style helpers across a live agent swarm are all described as design proposals in [`ai/SWARM_DESIGN.md`](ai/SWARM_DESIGN.md) (explicitly marked "Proposal / Vision" in that file) but are not implemented and tested the way the checkpointing and vector search primitives are. Treat anything not demonstrated in the linked demo or example as a direction, not a delivered feature. - -**Protocol interoperability, actually implemented.** `tools/mcpserver` and `tools/a2aagent` expose Joltrin runbooks to MCP and A2A clients respectively, both gated by a real safety-and-reachability barrier certificate (`ai/verify`) so a step can't execute out of order regardless of what a calling agent claims. Both protocols share one execution trace store, proven by a test that commits steps via one protocol and confirms the other sees them. See [MCP, A2A, and the Verification Engine](docs/MCP_A2A_AND_VERIFICATION_ENGINE.md) for the audit, the design, and an honest accounting of what this checker is and is not (it is not general-purpose LTL model checking). - -### โš™๏ธ For Platform, SRE & Cloud Engineers - -Joltrin Engine is a library, not a server: there is no separate database process to provision, patch, or fail over for the embedded case. The optional `tools/httpserver` Data Manager is a standalone service with its own `/metrics` endpoint (tested in `tools/httpserver/metrics_test.go`) if you do want a network-accessible console. Failure recovery is handled by Reed-Solomon erasure coding across storage shards (`fs/erasure`, 12 passing tests at the time of writing) rather than full N-way replication, which trades some recovery latency for lower disk overhead. A prebuilt quickstart container is published to `ghcr.io/sharedcode/joltrin-quickstart`. Multi-node swarm clustering exists and is tested (`examples/swarm_clustered`, `examples/swarm_standalone`), but has not been documented or proven at production scale. - -**Supply-Chain Security & Release Provenance:** Release builds are secured by an automated pre-publish quality gate ([`scripts/verify_release.sh`](scripts/verify_release.sh)), cryptographic SHA-256 manifests (`SHA256SUMS`), SPDX Software Bill of Materials (SBOM), and cryptographically signed build provenance attestations via GitHub Actions OIDC (`actions/attest-build-provenance`, SLSA Level 3 compliance). Consumers can independently verify any downloaded artifact using the standalone verification script. - -### ๐Ÿงช For Researchers & Distributed Systems Engineers - -The interesting parts to read are the B-Tree implementation with copy-on-write page isolation (`btree/`), the WAL plus two-phase commit transaction protocol (`transaction.go`, `common/`), the Reed-Solomon erasure coding layer (`fs/erasure/`), and the swarm coordination model described in [`ai/SWARM_DESIGN.md`](ai/SWARM_DESIGN.md). The [Architecture Whitepaper](docs/SOP_ARCHITECTURE_WHITEPAPER.md) and [Architecture vs. Big Tech](docs/ARCHITECTURE_VS_BIG_TECH.md) go deeper into the design tradeoffs than this README does. - -### ๐ŸŽ“ For Students & Learners - -Reading this codebase is a reasonable way to see real (not textbook-simplified) implementations of a B-Tree with node splitting and range iteration, optimistic concurrency control, write-ahead logging with two-phase commit, and erasure coding, all in readable Go with test coverage next to the implementation. Start with [`docs/WHAT_IS_SOP.md`](docs/WHAT_IS_SOP.md) for a plain-language overview, then run the zero-dependency quickstart below before reading `btree/` and `fs/erasure/`. - ---- - -## ๐Ÿ’Ž Monetization & Editions Architecture - -Joltrin follows an **Open-Core and Governance** architecture. The core database, vector similarity search, and agent memory engine are, and will always remain, **100% free and open-source under the permissive MIT License**. - -Commercial tiers are focused entirely on **enterprise governance, compliance, policy enforcement, multi-tenancy, and managed cloud infrastructure**, leaving the open-source core complete, unhindered, and unthrottled. - -For deep architectural documentation on package boundaries and code separation, see [Monetization & Governance Architecture](docs/MONETIZATION_AND_TIERS.md). - -| Tier / Edition | What It Provides | Distribution & Licensing | Implementation Status | -| :--- | :--- | :--- | :--- | -| **Free / Open-Source Core** | โ€ข Embedded copy-on-write B-Tree storage engine
โ€ข WAL + 2PC strict ACID transactions
โ€ข Reed-Solomon erasure coding and bitrot healing
โ€ข Durable AI agent memory & checkpointed buffers
โ€ข In-memory 128-d cosine vector similarity
โ€ข Embedded MCP server (`cmd/sop-mcp-server`)
โ€ข Embedded A2A agent runtime (`cmd/sop-a2a-agent`)
โ€ข Local runbook verification barrier (`ai/verify`)
โ€ข Developer GitHub OIDC authentication | Embedded Library & CLI
**Permissive MIT License** ($0) | **Available Today** | -| **Pro Governance** | โ€ข Policy-as-Code declarative runtime compiler
โ€ข Tamper-evident SHA-256 audit lineage & verification
โ€ข Signed cryptographic audit export
โ€ข Team-level workspaces and quota management
โ€ข Priority MCP gateways and traffic shaping
โ€ข Stripe Checkout, Customer Portal & Webhook Engine | Team Commercial Add-on
($49/team/mo) | **Available Today** ([`governance/`](governance/)) | -| **Enterprise Governance** | โ€ข Enterprise SSO: **Okta** & **Microsoft Entra ID**
โ€ข Multi-tenant RBAC & tenant isolation boundaries
โ€ข Enterprise audit streaming (real-time SIEM / Kafka)
โ€ข Fine-grained verification rules & custom safety invariants
โ€ข Custom invariant enforcement engine
โ€ข Enterprise compliance guarantees and SLA | Self-Hosted Enterprise Commercial
(Custom / Annual) | **Foundation Implemented** ([`governance/`](governance/)) | -| **Hosted Cloud** | โ€ข Managed Joltrin instances (zero-ops)
โ€ข Cloud-hosted MCP hub & multi-agent routing
โ€ข Multi-region database replication
โ€ข Managed agent coordination network
โ€ข Automated off-site snapshots & backup verification | Managed Cloud SaaS | **Planned** | - -### Open-Source Guarantees -- **No Artificial Paywalls**: The open-source core will never cap database size, transaction limits, memory buffers, or local MCP/A2A concurrency. -- **Permanent MIT License**: Core storage, vector search, and agent safety verification remain permanently open-source under the MIT license. -- **Decoupled Architecture**: Commercial and governance modules interact via clean, decoupled Go interfaces ([`governance/`](governance/)) rather than invasive runtime licensing checks. - -For a longer strategic view of enterprise defensibility and local-first architecture, see [Strategic Architecture & Investor Moat](docs/STRATEGIC_ARCHITECTURE_AND_MOAT.md). - ---- - -## ๐Ÿ—บ๏ธ Roadmap - -**Shipped and tested today**: the Go core engine, Python bindings (`sop4py`, on PyPI), C# bindings (`Sop`, on NuGet), the WebAssembly browser demo, the standalone HTTP Data Manager, and the interactive AI agent memory checkpointing demo. - -**In progress, code exists in-repo**: Java bindings (`sop4j`), complete with tests, blocked on Maven Central Portal credential setup rather than on missing functionality (see [`docs/RELEASE_PROCESS_JAVA_STATUS.md`](docs/RELEASE_PROCESS_JAVA_STATUS.md)). Rust bindings (`sop4rs`), with tests and examples in-repo, not yet published to crates.io. - -**Proposed, not yet implemented**: the swarm job distribution, `Await`, and `MapReduce` helpers described in [`ai/SWARM_DESIGN.md`](ai/SWARM_DESIGN.md), which that document itself labels "Proposal / Vision" rather than shipped. - -This list reflects what is actually in the repository at the time of writing. It is not a committed release schedule. - ---- - -## ๐ŸŒŽ Cross-Platform - -CI (`.github/workflows/ci.yml`) builds, vets, and runs the core unit tests (`inmemory`, `btree`, `common`, `cache`, `encoding`, `database`) on `ubuntu-latest`, `macos-latest`, and `windows-latest` on every push and pull request, as three independent, parallel jobs. `macos-latest` runs on Apple Silicon (arm64), so that leg also verifies arm64 for free. - -The Redis- and Cassandra-backed integration and stress test suites stay Linux-only: GitHub Actions' `services:` containers require a Linux-hosted runner, so those specific suites are not run on macOS or Windows today. That is a real gap in what is verified there, not a hidden one. All core unit test packages (`inmemory`, `btree`, `common`, `cache`, `encoding`, `database`) run and pass cleanly across all three operating systems (Linux, macOS, and Windows). - ---- - -## ๐Ÿ’ป For Developers - -### 1. In-Memory Quickstart (Zero Dependencies) - -```bash -# Clone the repository and run the quickstart -git clone https://github.com/sharedcode/joltrin.git -cd joltrin -go run ./examples/quickstart -``` - -```go -package main - -import ( - "fmt" - - "github.com/sharedcode/joltrin/v5/inmemory" -) - -func main() { - fmt.Println("Joltrin quickstart: in-memory ordered B-Tree") - - // Unique keys, string values. - b3 := inmemory.NewBtree[int, string](true) - - // Add a few build records keyed by build number. - builds := map[int]string{ - 101: "commit 9f2c1a build ok", - 102: "commit 4be77d build ok", - 103: "commit c30e52 tests failed", - 104: "commit 8d91f0 build ok", - 105: "commit 77aa3e released", - } - for k, v := range builds { - if !b3.Add(k, v) { - fmt.Printf("Add(%d) failed\n", k) - return - } - } - fmt.Printf("added %d items, count=%d\n", len(builds), b3.Count()) - - // Point lookup. - if b3.Find(103, true) { - fmt.Printf("Find(103): %s\n", b3.GetCurrentValue()) - } - - // Update in place. - b3.Update(103, "commit c30e52 tests fixed, build ok") - b3.Find(103, true) - fmt.Printf("after Update(103): %s\n", b3.GetCurrentValue()) - - // Ordered scan, no sort call needed: the tree keeps keys sorted. - fmt.Println("ordered scan:") - for k, v := range b3.All() { - fmt.Printf(" build %d -> %s\n", k, v) - } - - // Range scan seeks straight to the start key, then walks in order. - fmt.Println("range scan, builds 102-104:") - for k, v := range b3.Range(102, 104) { - fmt.Printf(" build %d -> %s\n", k, v) - } - - // Descending scan: newest builds first. - fmt.Println("descending scan, newest 3 builds:") - n := 0 - for k, v := range b3.AllDesc() { - fmt.Printf(" build %d -> %s\n", k, v) - if n++; n == 3 { - break - } - } - - fmt.Println("quickstart: OK") -} -``` - -This is the actual content of `examples/quickstart/main.go`, kept in sync here rather than paraphrased, so what you run and what you read match. - -### 2. AI Agent Memory & Swarm Task Hand-off - -Run the new dedicated Agent Memory demo: +## Try it in five minutes ```bash -go run ./examples/agent_memory +git clone https://github.com/sharedcode/joltrin.git && cd joltrin +go run ./examples/quickstart # ordered B-Tree with point, range, and descending scans +./scripts/demo.sh --barrier # the barrier blocks a database drop until a backup is validated +./scripts/demo.sh --memory # an agent crashes mid-task and a peer resumes from the B-Tree ``` -This demo demonstrates an AI worker creating a context checkpoint, crashing mid-step, rolling back cleanly, and having a healthy peer worker resume the task in `<15ms`. - ---- +Or skip the install. These run entirely in your browser with no backend: -## โšก Performance Benchmarks +| Live experience | What you do | +| :--- | :--- | +| [Technical demo](https://joltrinhq.com/) | Run ACID transactions, vector search, and an agent checkpoint resume on the WASM build of the engine. | +| [Agent barrier](https://joltrinhq.com/agents/) | Try to drop a database before the backup is validated and watch the barrier refuse. | +| [Arena](https://joltrinhq.com/arena/) | Crash storage nodes and spike load in a cluster simulation. It illustrates the concepts, it is not a live cluster. | -Below are benchmark results from the repository benchmark harness (`tools/benchmark`) run on a 2015 MacBook Pro (Dual-Core Intel Core i5, 8GB RAM, macOS). +## What is verified -What is measured: these runs benchmark Joltrin Engine's in-memory L2 cache with `/tmp` storage backing full ACID transactions, not disk-only storage without cache. +- **Latency.** About 6.9 microseconds per B-Tree write or read, over 140,000 ops/sec with WAL logging, from the repo's own harness on a 2015 dual-core MacBook Pro. Reproduce it with `go run ./tools/benchmark`. Details and limits are in [docs/BENCHMARKS.md](docs/BENCHMARKS.md). +- **Correctness.** The race detector runs on the core engine packages in CI, `govulncheck` runs on every push, and the build and unit tests run on Linux, macOS, and Windows. +- **Agent safety.** `ai/verify` is served over both MCP and A2A, and the same barrier compiles to WebAssembly for the browser demo. See [docs/AGENT_PROTOCOLS.md](docs/AGENT_PROTOCOLS.md). +- **Packages.** Published on PyPI (`sop4py`) and NuGet (`Sop`), plus the Go module. -### Microsecond-Scale Latency Profile +There are no documented production deployments or paying customers yet, and no third-party benchmarks. [docs/INVESTORS.md](docs/INVESTORS.md) lists what has and has not been proven. -The benchmark measurements confirm sub-millisecond execution down to microsecond item lookups: +## How it works -- **Embedded In-Process Latency**: `< 0.3ms` (<300ยตs) per transaction or safety barrier check, versus 15-50ms for multi-tier network round trips. -- **Per-Item Write Latency**: `~6.87ยตs` (at 145,417 ops/sec with full ACID WAL logging). -- **Per-Item Read Latency**: `~6.95ยตs` (at 143,770 ops/sec). -- **Swarm Failover & Re-assignment**: `< 15ms` heartbeat lease detection with automated rollback. - -Exact reproduction command: -```bash -go run ./tools/benchmark -count -slotlength ``` - -For example: -```bash -go run ./tools/benchmark -count 10000 -slotlength 2000 -go run ./tools/benchmark -count 100000 -slotlength 4000 -``` - -### Tuning `SlotLength` (Items per B-Tree Node) - -#### 10,000 Items Benchmark -| SlotLength | Insert (ops/sec) | Read (ops/sec) | Delete (ops/sec) | -| :--- | :--- | :--- | :--- | -| 1,000 | 107,652 | 136,754 | 40,964 | -| **2,000 (Balanced)** | **132,901** | **142,907** | **50,093** | -| 3,000 | 135,066 | 137,035 | 49,754 | -| 4,000 | 123,190 | 122,228 | 48,094 | - -#### 100,000 Items Benchmark -| SlotLength | Insert (ops/sec) | Read (ops/sec) | Delete (ops/sec) | -| :--- | :--- | :--- | :--- | -| 1,000 | 121,139 | 145,195 | 48,346 | -| 2,000 | 132,805 | 136,684 | 51,817 | -| 3,000 | 137,296 | 141,764 | 50,605 | -| **4,000 (Write-Heavy)** | **145,417** | 143,770 | **51,988** | - ---- - -## ๐Ÿ‘ฅ For Engineering Leaders & Hiring Managers - -For technical leaders, CTOs, and hiring managers, this repository serves as a working demonstration of systems engineering across: - -- **Storage Engine Design**: Custom B-Tree implementation with sector-aligned direct I/O, node slot tuning, and multi-tier L1/L2 caching. -- **Transactional Systems**: Strict ACID guarantees, Write-Ahead Logging (WAL), Two-Phase Commit (2PC), Snapshot Isolation, and Optimistic Concurrency Control. -- **Fault Tolerance & Reliability**: Reed-Solomon Erasure Coding (N+K striping), active/passive metadata redundancy, and automated partition healing. -- **High Concurrency**: Lock-free data structures, multi-goroutine worker swarms, and SIMD vector dot-product calculation. -- **Polyglot Architecture**: Native Go kernel, Python bindings (`sop4py`), C# bindings (`Sop`), and browser WebAssembly. -- **Production Delivery**: GitHub Actions CI/CD matrix, distroless container builds on GHCR, Codecov integration, and static GitHub Pages deployments. - -If you are building distributed systems, cloud infrastructure, or AI data platforms and want to discuss architecture, feel free to connect via [GitHub Discussions](https://github.com/SharedCode/joltrin/discussions). - ---- - -## ๐Ÿ“ฆ Language Packages & Tooling - -| Language | Installation | Description | -| :--- | :--- | :--- | -| **Go** | `go get github.com/sharedcode/joltrin/v5` | Native high-performance core engine. | -| **Python** | `pip install sop4py` | Python bindings with Data Manager and AI scripts. | -| **C#** | `dotnet add package Sop` | Complete .NET Core integration. | -| **WebAssembly** | `GOOS=js GOARCH=wasm go build` | Browser-sandboxed zero-server execution. | -| **HTTP Data Manager** | `sop-httpserver` | Standalone UI console and AI Copilot interface. | -| **Java** *(in progress)* | source in `bindings/java`, not yet on Maven Central | `sop4j` bindings and tests are complete; publishing is blocked on Central Portal credential setup, tracked in [`docs/RELEASE_PROCESS_JAVA_STATUS.md`](docs/RELEASE_PROCESS_JAVA_STATUS.md). | -| **Rust** *(in progress)* | source in `bindings/rust`, not yet on crates.io | `sop4rs` bindings, tests, and examples exist in-repo but are not yet published as a crate. | - -**Naming note:** Joltrin was called SOP until v5. The old names are unchanged so existing code keeps working: the Go package is still `sop`, the published packages are still `sop4py` and `Sop`, the binaries are still `sop-httpserver`, `sop-mcp-server`, `sop-a2a-agent` and `sop-a2a-bridge`, and the default data directory is still `/tmp/sop_data`. - -### How to Consume Joltrin: Releases vs. In-Repo Source - -When integrating Joltrin into your stack, choose between official versioned releases and in-repo source consumption based on your development and operational needs: - -| Dimension | Official Tagged Releases (Recommended for Production) | In-Repo Source / Submodule (Active Prototyping & Contribution) | -| :--- | :--- | :--- | -| **Artifacts** | `go get github.com/sharedcode/joltrin/v5@vX.Y.Z`
PyPI: `pip install sop4py`
NuGet: `dotnet add package Sop` | Git clone or submodule linked directly to `HEAD` or a feature branch | -| **Best For** | Production services, reproducible CI/CD builds, audited dependencies | Modifying engine internals, local benchmarking, custom protocol servers | -| **Stability** | Semantic versioning, tagged releases, audited dependency graph | Bleeding-edge features, experimental branches, unreleased protocol bridges | -| **Maintenance** | Handled by standard language package managers | Requires manual git fetch/rebase and local workspace management | - -#### 1. Official Tagged Releases (Recommended for Production) -For production deployments, pin your dependency to a tagged release. This guarantees reproducible builds, backward-compatible API guarantees, and security-scanned transitive dependencies: -- **Go**: `go get github.com/sharedcode/joltrin/v5@v5.7.0` (see [tags](https://github.com/sharedcode/joltrin/tags) for the latest) -- **Python**: `pip install sop4py==2.3.3` -- **C# / .NET**: `dotnet add package Sop --version 4.5.0` - -#### 2. In-Repo Source / Submodule (Prototyping & Contribution) -If you are extending storage engine internals (`btree/`, `fs/`), modifying protocol servers (`ai/verify`, `cmd/sop-mcp-server`, `cmd/sop-a2a-agent`), or benchmarking performance enhancements, consuming from source is recommended: -```bash -# Add as a git submodule in your project -git submodule add https://github.com/sharedcode/joltrin.git vendor/joltrin - -# Or configure a Go workspace (go.work) for local development -go work use ./vendor/joltrin + Application + | + | one in-process call + v ++----------------------------------------------------------+ +| Joltrin engine | +| copy-on-write B-Tree WAL + two-phase commit (ACID) | +| vector similarity search Reed-Solomon erasure coding | +| swarm task coordination ai/verify barrier (MCP, A2A) | ++----------------------------------------------------------+ ``` -### Cutting a Release (Maintainers) +Storage, queues, and coordination share one transaction boundary. If a worker dies, its uncommitted work rolls back and another worker takes the task. The long version is in [docs/WHY_JOLTRIN.md](docs/WHY_JOLTRIN.md) and [docs/SOP_ARCHITECTURE_WHITEPAPER.md](docs/SOP_ARCHITECTURE_WHITEPAPER.md). -Releases are cut from this repo with the scripts in `scripts/`, then tagged and pushed to GitHub. The full step-by-step for building native bindings and publishing to PyPI/NuGet/Maven is in [`RELEASE_PROCESS.md`](RELEASE_PROCESS.md); the short version: +## Install -```bash -# 1. Bump the version everywhere (VERSION file, go.mod-adjacent metadata, bindings) -./scripts/update_version.sh 5.8.0 +| Language | Command | +| :--- | :--- | +| Go | `go get github.com/sharedcode/joltrin/v5` | +| Python | `pip install sop4py` | +| C# | `dotnet add package Sop` | +| Container | `docker run ghcr.io/sharedcode/joltrin-quickstart:stable` | -# 2. Review the diff, then commit the bump -git add -A && git commit -m "bumped version to 5.8.0" +Java and Rust bindings exist in the repo and are not published yet. Version pinning, the naming note about the old SOP names, and the full package list are in [docs/PACKAGES.md](docs/PACKAGES.md). -# 3. Build release artifacts (native libs for Python/Java/C# bindings) -./scripts/build_release.sh +## Open core and plans -# 4. Verify checksums, archive integrity, and SBOM before publishing -./scripts/verify_release.sh release - -# 5. Tag and push. This is what makes `go get github.com/sharedcode/joltrin/v5@v5.8.0` resolve. -git tag v5.8.0 -git push origin master v5.8.0 - -# 6. Create the GitHub Release from the tag (attaches release notes + artifacts) -gh release create v5.8.0 --generate-notes -``` +The engine, vector search, agent memory, and the verification barrier are MIT licensed and stay free. Paid tiers add governance on top: -Go's package proxy needs no separate publish step: once the tag is pushed, `go get ...@v5.8.0` works immediately. Python, C#, and Java bindings still require the explicit `twine upload` / `dotnet nuget push` / `mvn deploy` steps in `RELEASE_PROCESS.md`. +- **Pro, $49 per team per month.** Policy-as-code, tamper-evident audit lineage, team workspaces. Billing runs through Stripe Checkout when a server is configured for it, otherwise it runs in simulation mode. +- **Enterprise, contact sales.** SSO, compliance exports, and custom policy rules. Use the contact form on [joltrinhq.com](https://joltrinhq.com/#enterprise). -## ๐Ÿ“š Technical Reference Guides +Tier details and the Stripe setup are in [docs/MONETIZATION_AND_TIERS.md](docs/MONETIZATION_AND_TIERS.md). -- **[What is Joltrin, in Plain Words](docs/WHAT_IS_SOP.md)**: High-level conceptual overview. -- **[Architecture Whitepaper](docs/SOP_ARCHITECTURE_WHITEPAPER.md)**: Deep dive into B-Tree layout and transactions. -- **[Platform Tools & Relational Intelligence](docs/SOP_PLATFORM_TOOLS.md)**: Data Manager, CEL expressions, and AI Copilot. -- **[AI Copilot & Agent Architecture](docs/AI_COPILOT.md)**: Multi-agent memory model and Space partitioning. -- **[Operations & Failover Guide](docs/OPERATIONS.md)**: Erasure coding, recovery, and cluster management. -- **[Scalability & Capacity Math](docs/SCALABILITY.md)**: Architectural scaling model for billions of items. +## Documentation ---- +- Start here: [What is Joltrin](docs/WHAT_IS_SOP.md), [Getting started](docs/GETTING_STARTED.md), [Examples](docs/EXAMPLES.md) +- Concepts: [Why Joltrin](docs/WHY_JOLTRIN.md), [Architecture](docs/SOP_ARCHITECTURE_WHITEPAPER.md), [Agent protocols](docs/AGENT_PROTOCOLS.md), [Scalability](docs/SCALABILITY.md) +- Operating it: [Operations and failover](docs/OPERATIONS.md), [Data Manager and tools](docs/SOP_PLATFORM_TOOLS.md), [Azure deployment](infra/azure/README.md) +- Reference: [Benchmarks](docs/BENCHMARKS.md), [Live demos](docs/LIVE_DEMOS.md), [Roadmap and platform support](docs/ROADMAP.md), [Who it is for](docs/WHO_IS_IT_FOR.md), [Investor notes](docs/INVESTORS.md) -## ๐Ÿค Get Involved +## Contributing -We welcome feedback, issues, and contributions: +Run `go test ./...` and `gofmt` before opening a pull request, and include tests with your change. See [CONTRIBUTING.md](CONTRIBUTING.md) and [SECURITY.md](SECURITY.md). Questions and ideas go to [GitHub Discussions](https://github.com/SharedCode/joltrin/discussions). -1. **Fork & Clone**: `git clone https://github.com/sharedcode/joltrin.git` -2. **Run Tests**: `go test -v ./...` -3. **Join Discussions**: [GitHub Discussions](https://github.com/SharedCode/joltrin/discussions) -4. **Submit a PR**: Follow Go formatting standards (`gofmt`) and include test coverage. +## Releases ---- +See the [changelog](CHANGELOG.md) and the [releases page](https://github.com/SharedCode/joltrin/releases). Maintainers cut releases with [RELEASE_PROCESS.md](RELEASE_PROCESS.md) and the short version in [docs/PACKAGES.md](docs/PACKAGES.md).

- Licensed under the MIT License. Built by SharedCode. + MIT License. Built by SharedCode.

diff --git a/VERSION b/VERSION index 1bc788d3b..11d9efa3d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.6.0 +5.8.0 diff --git a/bindings/csharp/Sop.CLI/Sop.CLI.csproj b/bindings/csharp/Sop.CLI/Sop.CLI.csproj index c79cc251b..a9cf5bf68 100644 --- a/bindings/csharp/Sop.CLI/Sop.CLI.csproj +++ b/bindings/csharp/Sop.CLI/Sop.CLI.csproj @@ -10,7 +10,7 @@ true sop-cli Sop4CS.CLI - 5.6.0 + 5.8.0 Gerardo Recinto SOP CLI and Examples MIT diff --git a/bindings/csharp/Sop.HttpServer/Sop.HttpServer.csproj b/bindings/csharp/Sop.HttpServer/Sop.HttpServer.csproj index 4b1515c31..055289f5f 100644 --- a/bindings/csharp/Sop.HttpServer/Sop.HttpServer.csproj +++ b/bindings/csharp/Sop.HttpServer/Sop.HttpServer.csproj @@ -10,7 +10,7 @@ true sop-httpserver Sop4CS.HttpServer - 5.6.0 + 5.8.0 Gerardo Recinto SOP HTTP Server and Data Management Console MIT diff --git a/bindings/csharp/Sop/Sop.csproj b/bindings/csharp/Sop/Sop.csproj index 3210f4624..534b5e6a5 100644 --- a/bindings/csharp/Sop/Sop.csproj +++ b/bindings/csharp/Sop/Sop.csproj @@ -3,7 +3,7 @@ netstandard2.0 Sop4CS - 5.6.0 + 5.8.0 Gerardo Recinto Joltrin (distributed as Sop4CS) - Durable memory and verification infrastructure for AI agents. database;btree;vector;storage;transactional;ai-memory diff --git a/bindings/csharp/VERSION b/bindings/csharp/VERSION index 1bc788d3b..11d9efa3d 100644 --- a/bindings/csharp/VERSION +++ b/bindings/csharp/VERSION @@ -1 +1 @@ -5.6.0 +5.8.0 diff --git a/bindings/java/pom.xml b/bindings/java/pom.xml index b845877c6..382957a64 100644 --- a/bindings/java/pom.xml +++ b/bindings/java/pom.xml @@ -5,7 +5,7 @@ io.github.sharedcode sop4j - 5.6.0 + 5.8.0 jar SOP Java Binding diff --git a/bindings/python/README.md b/bindings/python/README.md index eee434797..c394bb057 100644 --- a/bindings/python/README.md +++ b/bindings/python/README.md @@ -34,7 +34,7 @@ The **SOP AI Kit** transforms SOP from a storage engine into a complete AI data * **RAG Agents**: Build Retrieval-Augmented Generation applications with ease. * **Scripts**: A functional AI runtime for drafting, refining, and executing complex workflows (Hybrid Execution Model). -> **Important**: To use the AI Copilot features (e.g., in the Data Manager), configure your LLM provider through the Setup Wizard or add generator configuration to your `config.json`. See the [Main README](../../README.md#ai-copilot-configuration) for details. +> **Important**: To use the AI Copilot features (e.g., in the Data Manager), configure your LLM provider through the Setup Wizard or add generator configuration to your `config.json`. See the [Main README](../../docs/AI_COPILOT.md) for details. For comprehensive details on the **SOP Platform Tools** (Scripting, Explain Plans, Self-Correcting Agents), please see the [Platform Tools Documentation](../../docs/SOP_PLATFORM_TOOLS.md). diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index f84ceb838..9e7f97fdb 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "sop4py" -version = "5.6.0" +version = "5.8.0" authors = [ { name="Gerardo Recinto", email="gerardorecinto@yahoo.com" }, ] diff --git a/bindings/python/sop/__init__.py b/bindings/python/sop/__init__.py index 83343bc5e..62b159ee4 100644 --- a/bindings/python/sop/__init__.py +++ b/bindings/python/sop/__init__.py @@ -1,6 +1,6 @@ -__version__="5.6.0" +__version__="5.8.0" from . import ai from .transaction import Transaction, TransactionOptions, TransactionMode diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml index 86a97da0d..988672e3d 100644 --- a/bindings/rust/Cargo.toml +++ b/bindings/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sop" -version = "5.6.0" +version = "5.8.0" edition = "2021" description = "Rust bindings for Joltrin (formerly SOP)" license = "MIT" diff --git a/demo-agents/index.html b/demo-agents/index.html index c4e53d71f..229b4ec53 100644 --- a/demo-agents/index.html +++ b/demo-agents/index.html @@ -6,21 +6,21 @@ Joltrin Agents | Durable Memory, State & Verification Barrier for AI - + - + - + - + - + diff --git a/demo/CNAME b/demo/CNAME index 77ed06066..bfe303b8f 100644 --- a/demo/CNAME +++ b/demo/CNAME @@ -1 +1 @@ -joltrin.com +joltrinhq.com diff --git a/demo/index.html b/demo/index.html index 256af1302..b53020dea 100644 --- a/demo/index.html +++ b/demo/index.html @@ -6,21 +6,21 @@ Joltrin | Verification Barrier & Durable Memory for AI Agents | Embedded ACID Engine - + - + - + - + - + @@ -312,9 +312,9 @@
Joltrin - v1.0 WASM + WASM demo
- +
@@ -345,7 +345,7 @@
-

Open Source & Community

@@ -2132,9 +1474,7 @@

Open Source &a
ยฉ 2026 Joltrin Authors & SharedCode. Open source core under MIT license.
- Sub-millisecond ACID Latency - โ€ข - Zero Unverified Actions + Docs on GitHub
@@ -2759,11 +2099,11 @@

${res.title}

// GitHub Pages deployment, which serves static files only). Be honest // about that instead of faking a checkout session. btn.disabled = false; - btnText.innerText = 'Proceed to Secure Stripe Checkout โ†’'; + btnText.innerText = 'Request Pro'; const mailtoSubject = encodeURIComponent(`Joltrin Pro signup: ${workspace}`); const mailtoBody = encodeURIComponent( - `Workspace: ${workspace}\nEmail: ${email}\nBilling cycle: ${cycle === 'annual' ? 'Annual ($490/year)' : 'Monthly ($49/month)'}` + `Workspace: ${workspace}\nEmail: ${email}\nPlan: Pro ($49/month)` ); const mailtoLink = `mailto:gerardrecinto@gmail.com?subject=${mailtoSubject}&body=${mailtoBody}`; @@ -2772,10 +2112,10 @@

${res.title}

statusBox.innerHTML = `
- Checkout isn't live on this static site yet + Online checkout isn't available on this site yet

- This demo is hosted on GitHub Pages, which can't run the billing backend. Email us your workspace name and we'll set up ${workspace} on the ${cycle === 'annual' ? '$490/year' : '$49/month'} plan directly. + This site is hosted on GitHub Pages, which can't run the billing backend. Email us your workspace name and we'll set up ${workspace} on the $49/month plan directly.

diff --git a/docs/AGENT_PROTOCOLS.md b/docs/AGENT_PROTOCOLS.md new file mode 100644 index 000000000..b064e393b --- /dev/null +++ b/docs/AGENT_PROTOCOLS.md @@ -0,0 +1,119 @@ +# Agent protocols: MCP, A2A, and the verification barrier + +Joltrin runbooks are reachable from two agent protocols, [Model Context Protocol](https://modelcontextprotocol.io/) and [Agent2Agent](https://a2a-protocol.org/), both gated by the same safety-and-reachability check before a step is allowed to commit. Real, tested code (`ai/verify`, `tools/mcpserver`, `tools/a2aagent`), not a diagram of an idea; see [MCP, A2A, and the Verification Engine](MCP_A2A_AND_VERIFICATION_ENGINE.md) for the full audit and design writeup. + +

+ An MCP client and an A2A orchestrator each reach a separate protocol server, both backed by the same tools/runbookstore.Store and gated by the same ai/verify safety check before a step commits +

+ +**Try the barrier yourself, live: [joltrinhq.com/agents](https://joltrinhq.com/agents/).** GitHub Pages can't run a real MCP or A2A network server (no backend), so this page runs the actual `ai/verify` check compiled to WASM, wired to buttons instead of protocol calls, the same logic those servers call before committing a step. Click "Drop Prod DB" first and watch it block; the trace persists to OPFS, so a reload picks up where you left off. This is a real recording of that page, not a mockup: + +

+ Real browser recording of the live agent verification barrier demo: dropping the database is blocked until backup and validation steps actually commit, then the same drop is allowed +

+ +The same scenario also runs as a terminal program, `examples/verify_barrier`, and the servers themselves are one command away: + +

+ Real terminal recording of ai/verify blocking a database drop until a backup is validated, then allowing it once the precondition is actually met +

+ +```bash +# Run the barrier demo yourself +go run ./examples/verify_barrier + +# Serve the same runbook over MCP (stdio) +# Note: this speaks JSON-RPC over stdin/stdout for an MCP client (Claude +# Desktop, an SDK, etc). Run bare in a terminal, it'll print "Parse error" +# for every line you type, since your keystrokes aren't valid JSON-RPC - +# that's expected, not a bug. Point an MCP client at this command instead. +go run ./cmd/sop-mcp-server + +# Serve it over A2A instead, then fetch its agent card +go run ./cmd/sop-a2a-agent & +curl localhost:8087/.well-known/agent-card.json + +# Claude has no native A2A client, so bridge the two: sop-a2a-bridge +# resolves the agent card above and re-exposes execute_step as an MCP tool +go run ./cmd/sop-a2a-bridge -agent-url http://localhost:8087 +``` + +### Wiring `sop-mcp-server` into Claude + +`cmd/sop-mcp-server` speaks JSON-RPC over stdio and evaluates the barrier policies below (`ai/verify`'s `CheckSafety`) before `execute_step` is allowed to commit; a blocked step comes back as `input-required`, not a crash. Point either Claude client at the command: + +**Claude Desktop** (`claude_desktop_config.json`, stdio transport): + +```json +{ + "mcpServers": { + "joltrin": { + "command": "go", + "args": ["run", "./cmd/sop-mcp-server"], + "cwd": "/absolute/path/to/joltrin" + } + } +} +``` + +Swap `"command"/"args"` for a prebuilt binary once you've run `go build -o sop-mcp-server ./cmd/sop-mcp-server`: + +```json +{ + "mcpServers": { + "joltrin": { + "command": "/absolute/path/to/joltrin/sop-mcp-server" + } + } +} +``` + +**Claude Code** (CLI): + +```bash +claude mcp add --transport stdio joltrin -- go run ./cmd/sop-mcp-server +``` + +### Wiring `sop-a2a-agent` into Claude (via `sop-a2a-bridge`) + +Claude doesn't speak A2A natively, MCP is the protocol its clients actually implement, so reaching an A2A agent means bridging the two, not writing an A2A client into Claude itself. `tools/a2abridge` is that bridge: an MCP server that resolves a running `sop-a2a-agent`'s card and re-exposes its `execute_step` skill as an MCP tool of the same name, translating each call into a real A2A task delegation over the wire and translating the resulting task state (`completed` / `input-required` / `failed`) back into an MCP tool result. It's built on the official `a2aclient` SDK package, not a hand-rolled JSON-RPC client, and it's covered by its own integration tests (`tools/a2abridge/bridge_test.go`) that drive the full MCP -> bridge -> real A2A wire protocol -> executor round trip, including the blocked, allowed, and remote-failure paths. + +Start the agent, then point the bridge at it: + +```bash +go run ./cmd/sop-a2a-agent & +go run ./cmd/sop-a2a-bridge -agent-url http://localhost:8087 +``` + +**Claude Desktop:** + +```json +{ + "mcpServers": { + "joltrin-a2a": { + "command": "go", + "args": ["run", "./cmd/sop-a2a-bridge", "-agent-url", "http://localhost:8087"], + "cwd": "/absolute/path/to/joltrin" + } + } +} +``` + +**Claude Code** (CLI): + +```bash +claude mcp add --transport stdio joltrin-a2a -- go run ./cmd/sop-a2a-bridge -agent-url http://localhost:8087 +``` + +### Barrier policies `ai/verify` enforces + +`ai/verify` is a general-purpose explicit-state precondition/postcondition graph (`Step`, `SafetyRule`, `ReachabilityRule` in `ai/verify/verify.go`) with no built-in notion of databases, clusters, or money. Every state is an opaque string, so a barrier policy for any category of risky action is defined the same way: name the states that must hold, name the step that establishes the dangerous one, and let `CheckSafety` gate it. This repo ships three concrete runbooks in `tools/runbookstore` built on that same generic mechanism, one per risky-action category, plus the generic out-of-order rejection that applies to all of them: + +- **Destructive operations** (`DBMaintenanceWorkflow`, e.g. dropping a database): `drop_prod_db` requires `backup_validated`, which only `validate_backup` establishes after `take_backup`. A `SafetyRule` (`no-drop-without-validated-backup`) names the barrier explicitly, and a `ReachabilityRule` guarantees `rollback_complete` stays reachable even after the drop. +- **Resource & topology mutations** (`ClusterTopologyWorkflow`, e.g. draining a node, failing over a cluster): `drain_node` and `failover_cluster` both require `replica_parity_verified`, which requires `health_check_passed` first. Reinstating the node or cluster (`topology_rollback_complete`) stays reachable from every state in the graph, including after a worker is terminated post-drain. +- **Financial / ledger-mutating actions** (`LedgerTransferWorkflow`, e.g. balance updates, account transfers): `commit_transfer` requires `zero_sum_verified`, which only `verify_zero_sum_invariant` establishes after balances are mutated inside a `transaction_serialized` scope (`begin_serializable_transaction` -> `snapshot_balances` -> `apply_debit_credit`). Reversal (`ledger_rollback_complete`) stays reachable both before and after commit. +- **Unverified / out-of-order execution**: this is the same mechanism underlying all three, not a separate check. `CheckSafety` rejects any step whose `Requires` states haven't been established yet in the current `Trace`, and rejects any step that would establish a `Forbidden` state without its paired `Requires` state already holding. An agent (or a client bug) trying to call `drain_node` or `commit_transfer` before its preconditions land gets a named, actionable violation back, never a silent no-op. + +Only `DBMaintenanceWorkflow` is registered by the example binaries (`cmd/sop-mcp-server`, `cmd/sop-a2a-agent`) today; `ClusterTopologyWorkflow` and `LedgerTransferWorkflow` are available in `tools/runbookstore` (with tests in `tools/runbookstore/examples_test.go`) as worked examples of modeling the other two categories on the same engine. Register them with `store.RegisterWorkflow` in your own server to serve them. + +What this checker is, precisely, matters more than what it sounds like it might be: explicit-state safety and reachability checking over a finite workflow graph, the "P is preceded by Q" precedence pattern from Dwyer/Avrunin/Corbett's property specification patterns (ICSE 1999), not general-purpose LTL/CTL model checking. No formula parser, no Bรผchi automata, no neural component translating natural language into the graph today. The full accounting of what's built versus proposed is in the linked doc, not summarized rosily here. diff --git a/docs/BENCHMARKS.md b/docs/BENCHMARKS.md new file mode 100644 index 000000000..1db1ccfbf --- /dev/null +++ b/docs/BENCHMARKS.md @@ -0,0 +1,61 @@ +# Benchmarks and engineering proof + +What is measured in this repository, how to reproduce it, and what the numbers do not show. + +### Engineering ROI, Verified in This Repo + +No revenue or customer numbers exist yet for this project (see [For Investors](INVESTORS.md) for the honest version of that). What is verified today, in this repo, is the infrastructure cost this architecture removes: + +| What collapses | From | To | +| :--- | :--- | :--- | +| **Network hops per operation** | 3 hops across Redis, a queue, and Postgres/Cassandra (estimated 15-50ms network round-trip overhead) | 1 embedded in-process call (<0.3ms measured latency, >145k ops/sec) | +| **Stateful services to operate, patch, and page on** | Redis + Kafka/RabbitMQ + Postgres/Cassandra + ZooKeeper (4+) | 1 embedded library | +| **Language surfaces shipped** | N/A | Go (native), Python (`sop4py` on PyPI), C# (`Sop` on NuGet); Java and Rust bindings exist in-repo with tests, not yet published | +| **CI rigor on every change** | N/A | `govulncheck` clean on every push; race detector on the core engine packages (`btree`, `common`, `fs`, `inmemory`); 3-OS build and test matrix (Linux, macOS, Windows) | +| **Deployment footprint of the technical demo** | A server-backed demo stack | WASM build running ACID transactions, vector search, and agent-memory checkpointing 100% client-side, 0 runtime HTTP calls after page load ([live](https://joltrinhq.com/)) | + +Every row above is something you can run yourself, not a projection. See [Performance Benchmarks](#performance-benchmarks) for the throughput numbers behind the latency claim, and [What Has Not Yet Been Proven](INVESTORS.md) for what this table deliberately leaves out. + +## Performance Benchmarks + +Below are benchmark results from the repository benchmark harness (`tools/benchmark`) run on a 2015 MacBook Pro (Dual-Core Intel Core i5, 8GB RAM, macOS). + +What is measured: these runs benchmark Joltrin Engine's in-memory L2 cache with `/tmp` storage backing full ACID transactions, not disk-only storage without cache. + +### Microsecond-Scale Latency Profile + +The benchmark measurements confirm sub-millisecond execution down to microsecond item lookups: + +- **Embedded In-Process Latency**: `< 0.3ms` (<300ยตs) per transaction or safety barrier check, versus 15-50ms for multi-tier network round trips. +- **Per-Item Write Latency**: `~6.87ยตs` (at 145,417 ops/sec with full ACID WAL logging). +- **Per-Item Read Latency**: `~6.95ยตs` (at 143,770 ops/sec). +- **Swarm Failover & Re-assignment**: `< 15ms` heartbeat lease detection with automated rollback. + +Exact reproduction command: +```bash +go run ./tools/benchmark -count -slotlength +``` + +For example: +```bash +go run ./tools/benchmark -count 10000 -slotlength 2000 +go run ./tools/benchmark -count 100000 -slotlength 4000 +``` + +### Tuning `SlotLength` (Items per B-Tree Node) + +#### 10,000 Items Benchmark +| SlotLength | Insert (ops/sec) | Read (ops/sec) | Delete (ops/sec) | +| :--- | :--- | :--- | :--- | +| 1,000 | 107,652 | 136,754 | 40,964 | +| **2,000 (Balanced)** | **132,901** | **142,907** | **50,093** | +| 3,000 | 135,066 | 137,035 | 49,754 | +| 4,000 | 123,190 | 122,228 | 48,094 | + +#### 100,000 Items Benchmark +| SlotLength | Insert (ops/sec) | Read (ops/sec) | Delete (ops/sec) | +| :--- | :--- | :--- | :--- | +| 1,000 | 121,139 | 145,195 | 48,346 | +| 2,000 | 132,805 | 136,684 | 51,817 | +| 3,000 | 137,296 | 141,764 | 50,605 | +| **4,000 (Write-Heavy)** | **145,417** | 143,770 | **51,988** | diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md new file mode 100644 index 000000000..e09a8ac60 --- /dev/null +++ b/docs/EXAMPLES.md @@ -0,0 +1,89 @@ +# Examples + +## 1. In-Memory Quickstart (Zero Dependencies) + +```bash +# Clone the repository and run the quickstart +git clone https://github.com/sharedcode/joltrin.git +cd joltrin +go run ./examples/quickstart +``` + +```go +package main + +import ( + "fmt" + + "github.com/sharedcode/joltrin/v5/inmemory" +) + +func main() { + fmt.Println("Joltrin quickstart: in-memory ordered B-Tree") + + // Unique keys, string values. + b3 := inmemory.NewBtree[int, string](true) + + // Add a few build records keyed by build number. + builds := map[int]string{ + 101: "commit 9f2c1a build ok", + 102: "commit 4be77d build ok", + 103: "commit c30e52 tests failed", + 104: "commit 8d91f0 build ok", + 105: "commit 77aa3e released", + } + for k, v := range builds { + if !b3.Add(k, v) { + fmt.Printf("Add(%d) failed\n", k) + return + } + } + fmt.Printf("added %d items, count=%d\n", len(builds), b3.Count()) + + // Point lookup. + if b3.Find(103, true) { + fmt.Printf("Find(103): %s\n", b3.GetCurrentValue()) + } + + // Update in place. + b3.Update(103, "commit c30e52 tests fixed, build ok") + b3.Find(103, true) + fmt.Printf("after Update(103): %s\n", b3.GetCurrentValue()) + + // Ordered scan, no sort call needed: the tree keeps keys sorted. + fmt.Println("ordered scan:") + for k, v := range b3.All() { + fmt.Printf(" build %d -> %s\n", k, v) + } + + // Range scan seeks straight to the start key, then walks in order. + fmt.Println("range scan, builds 102-104:") + for k, v := range b3.Range(102, 104) { + fmt.Printf(" build %d -> %s\n", k, v) + } + + // Descending scan: newest builds first. + fmt.Println("descending scan, newest 3 builds:") + n := 0 + for k, v := range b3.AllDesc() { + fmt.Printf(" build %d -> %s\n", k, v) + if n++; n == 3 { + break + } + } + + fmt.Println("quickstart: OK") +} +``` + +This is the actual content of `examples/quickstart/main.go`, kept in sync here rather than paraphrased, so what you run and what you read match. + +## 2. AI Agent Memory & Swarm Task Hand-off + +Run the new dedicated Agent Memory demo: + +```bash +go run ./examples/agent_memory +``` + +This demo demonstrates an AI worker creating a context checkpoint, crashing mid-step, rolling back cleanly, and having a healthy peer worker resume the task in `<15ms`. diff --git a/docs/INVESTORS.md b/docs/INVESTORS.md new file mode 100644 index 000000000..841077e1b --- /dev/null +++ b/docs/INVESTORS.md @@ -0,0 +1,50 @@ +# Notes for investors + +What has and has not been proven. No revenue, customer, or market-size figures are claimed anywhere in this repository. + +### For Investors + +**The problem.** Teams building stateful distributed applications, agent systems especially, routinely wire together a database, a cache, a message queue, a lock manager, and a workflow engine just to get durable state and coordinated work. Each boundary between those systems is a place where consistency breaks during a partial failure. That integration tax is paid by every team that builds this kind of system, repeatedly. + +**What Joltrin uniquely combines.** A B-Tree storage engine, ACID transactions, and swarm task coordination live inside one embedded library instead of behind separate network services. That is an architectural bet, not a settled fact: it trades the maturity and ecosystem of specialized tools (Postgres, Kafka, Temporal) for fewer moving parts and a single consistency boundary. Whether that tradeoff wins in a given workload is something a team has to evaluate, which is exactly what the [comparison table](WHY_JOLTRIN.md#joltrin-vs-alternatives) below is for. + +**Investment Thesis** +Joltrin is an open-source bet that "data plus compute in one embedded engine" is a better default for a growing category of workloads (AI agents, edge devices, real-time systems) than assembling that stack from five separate products. If that thesis is right, the project that owns the reference implementation of that architecture has a shot at becoming the default choice for it, the way SQLite became the default embedded relational store. That is a multi-year distribution bet, not a proven outcome. + +**Why Now** +- AI agent systems increasingly need durable memory, checkpointing, and multi-worker coordination, and today that is usually stitched together from a vector database, a cache, and a job queue. +- Edge and local-first computing (factory automation, vehicles, retail devices) need ACID storage that keeps working without a constant connection to a central database. +- Engineering organizations are actively trying to cut the number of discrete stateful services they operate, both for cost and for on-call load. + +These are real, observable industry trends. No specific market-sizing figures are cited here because this repository has not commissioned or verified any (see Market Opportunity below). + +**Market Opportunity** +Joltrin overlaps several existing categories rather than creating one from nothing: embedded databases (SQLite, RocksDB), distributed coordination (Zookeeper, etcd, Temporal), vector databases (Pinecone, Weaviate, pgvector), and workflow/task systems (Celery, Ray). Plausible buyers are teams building AI agent infrastructure, edge and IoT platforms, real-time/simulation backends, and fintech ledgers with strict transactional invariants. No independently sourced TAM/SAM/SOM figures are presented here; a rigorous estimate would require external market research (for example, from Gartner or IDC) that this project has not commissioned. + +**Business Model Opportunities** +The core is MIT-licensed. Commercial governance features (policy-as-code, audit lineage, billing) exist as code in `governance/`, but no revenue or paying customers are documented in this repository. Whether Pro checkout is live depends on production Stripe configuration, not on the code. The open-core progression and architectural foundations for commercial governance are detailed in [Monetization and Tiers](MONETIZATION_AND_TIERS.md). + +**What Has Been Proven** +- A working Go engine with ACID transactions (WAL plus two-phase commit), a custom B-Tree, and Reed-Solomon erasure coding, each with passing automated tests (23 packages carry tests in the core Go module; run them with `go test ./...`, while the two WASM-only packages build under `GOOS=js GOARCH=wasm`, see [Performance Benchmarks](BENCHMARKS.md#performance-benchmarks) below for the throughput numbers). +- A real WebAssembly build of the engine running ACID transactions, vector search, and agent-memory checkpointing entirely in-browser with zero runtime network calls after initial page load ([live demo](https://joltrinhq.com/)). +- Working language bindings for Go (native), Python (`sop4py`, published to PyPI), and C# (`Sop`, published to NuGet), plus Java and Rust bindings that exist in-repo with tests but are not yet published to their package registries. +- CI that runs the race detector and `govulncheck` on every change, and a changelog showing multiple rounds of real dependency and CVE remediation. + +**What Has Not Yet Been Proven** +- No production deployments or paying customers are documented anywhere in this repository. +- No independent, third-party, or peer-reviewed benchmarks exist; the performance numbers below come from this project's own benchmark harness on a single workstation, not a controlled multi-system comparison. +- Joltrin Arena's cluster view is a UI simulation of the underlying concepts for demonstration purposes, not a live multi-node deployment; multi-node swarm clustering itself is real and tested (`examples/swarm_clustered`, `examples/swarm_standalone`), but has not been run at meaningful scale or under adversarial network conditions in public. +- No formal third-party security audit has been performed. +- No case studies, design partners, or committed customers exist yet. + +### For Investment Banking & Technology Finance + +**Technology category.** Joltrin sits in the embedded data infrastructure layer: a storage and coordination engine that applications link against directly, similar in category placement to SQLite or RocksDB, but extended with distributed ACID transactions and task coordination that those two do not attempt. + +**Adjacent markets.** Embedded/operational databases, distributed coordination and workflow orchestration, vector search infrastructure, and AI agent infrastructure tooling. Each of those adjacent markets has established commercial players (see the [comparison table](WHY_JOLTRIN.md#joltrin-vs-alternatives)), which is useful context for sizing the competitive landscape Joltrin would need to differentiate against. + +**Potential strategic relevance.** This could include: infrastructure vendors looking to add an embedded, agent-friendly storage layer to an existing platform; cloud providers evaluating lightweight alternatives to running separate managed database, cache, and queue services for edge or agent workloads; or AI infrastructure companies needing a durable state layer under an agent runtime. None of this reflects any actual approach, interest, or discussion from any party; it is offered as a way to reason about where the technology could fit strategically. + +**Open-source distribution.** The core is distributed under the MIT license, so any team can use it in production immediately. Commercial tiers add governance features on top, and none of them are required to use the engine. See [Monetization and Tiers](MONETIZATION_AND_TIERS.md) for the open-core progression and architectural separation. + +**Competitive landscape.** Summarized in the [Joltrin vs. Alternatives](WHY_JOLTRIN.md#joltrin-vs-alternatives) table further down. No competitor is presented as inferior; each is a mature, widely deployed system that Joltrin would need to displace or complement for any given workload. diff --git a/docs/LIVE_DEMOS.md b/docs/LIVE_DEMOS.md new file mode 100644 index 000000000..1d5fad544 --- /dev/null +++ b/docs/LIVE_DEMOS.md @@ -0,0 +1,34 @@ +# Live demos + +Three browser experiences run from the same engine. None of them need a backend. + +| Experience | Description | Live Interactive Link | +| :--- | :--- | :--- | +| **Joltrin Technical Demo** | **Client-Side Zero-Server WebAssembly Engine**
Execute live ACID transactions, 128-dimensional vector cosine searches, microsecond benchmarks, and durable AI agent memory checkpoints (kill the agent mid-task, watch a successor resume from the B-Tree) running 100% in your browser with **0 runtime HTTP network calls after initial load**. | [**Launch Technical Demo โ†’**](https://joltrinhq.com/) | +| **Joltrin Arena** | **Distributed Systems Survival Simulation**
Command a live digital cluster. Scale worker swarms, crash storage nodes, trigger transaction storms, and watch Joltrin automatically redistribute tasks and rebuild parity in real-time. | [**Play Joltrin Arena โ†’**](https://joltrinhq.com/arena/) | +| **Joltrin Agent Verification Barrier** | **The MCP/A2A Safety Check, Clickable**
The same `ai/verify` barrier gating `tools/mcpserver` and `tools/a2aagent`, compiled to WASM. Try dropping a database before validating a backup and watch it get blocked, in your browser, with the trace persisted to OPFS. | [**Launch Agent Barrier โ†’**](https://joltrinhq.com/agents/) | + +## Experience Joltrin + +You can test Joltrin directly in your browser without installing anything via the live interactive experiences above ([Technical Demo](https://joltrinhq.com/), [Joltrin Arena](https://joltrinhq.com/arena/), and [Agent Verification Barrier](https://joltrinhq.com/agents/)). The technical demo demonstrates the engine's core power directly: safe, ACID-transactional storage running on web storage itself (OPFS), with zero server and zero network calls after the initial page loads the WASM binary. Everything else on this page, including the agent verification barrier below, is built on top of that same engine, a reference implementation showing one concrete use case. + +The technical demo persists across reloads now, to Origin Private File System, via the browser's async File System Access API. The diagram below is the real tradeoff behind that choice, not a benchmark; no throughput numbers are shown because none have been measured for either path in this repo. + +

+ OPFS persistence: the async File System Access API path this repo built, versus the synchronous createSyncAccessHandle path that would require moving the WASM binary into a dedicated Worker, deliberately not built this pass +

+ +That same WASM-compiled engine is what the Agent Verification Barrier row above actually runs on, not a separate reimplementation: it's the concrete reference implementation this repo ships to answer "what do you actually build with a durable, transactional engine running client-side?" It is an AI agent safety check an agent cannot talk its way around, with the trace itself durable in OPFS across reloads. The next section is that barrier in depth, plus the same check reachable server-side over MCP and A2A. + +## See Joltrin in Action (Joltrin Arena Simulation) + +In **[Joltrin Arena](https://joltrinhq.com/arena/)**, every control maps directly to a real distributed systems concept: + +| Simulation Control | Distributed Systems Concept | Joltrin Technical Mechanism | +| :--- | :--- | :--- | +| **Add Worker** | Swarm Compute | Dynamic queue rebalancing across peer worker nodes without central master bottlenecks. | +| **Remove Worker** | Graceful Degradation | Active tasks drained and re-assigned to healthy nodes with zero dropped writes. | +| **Kill Node / Storage Fault** | Fault Tolerance | **Reed-Solomon Erasure Coding** reconstructs missing B-Tree blocks in-memory from parity chunks. | +| **Transaction Storm** | Concurrency & Isolation | **Optimistic Concurrency Control (OCC)** serializes conflicting writes in microseconds. | +| **Increase Workload (100k TPS)** | Scalability | B-Tree node segments partition write load across sector-aligned storage handles. | +| **Automatic Self-Healing** | Resilient Coordination | Heartbeat lease detection triggers automated task redistribution in `<15ms`. | diff --git a/docs/MONETIZATION_AND_TIERS.md b/docs/MONETIZATION_AND_TIERS.md index 3046d7efd..9b21210db 100644 --- a/docs/MONETIZATION_AND_TIERS.md +++ b/docs/MONETIZATION_AND_TIERS.md @@ -34,12 +34,27 @@ To maintain clean separation between the open-source storage engine and commerci - Constant-time signature comparison protects against timing side-channel attacks. - **Idempotent Webhook Processing (`HandleWebhook`)**: - Automatically deduplicates re-delivered Stripe events using a thread-safe event cache. - - Handles `checkout.session.completed`, `customer.subscription.created/updated`, and `customer.subscription.deleted`. + - Handles `checkout.session.completed`, `customer.subscription.created/updated`, `customer.subscription.deleted`, `invoice.payment_succeeded`, and `invoice.payment_failed`. + - A live deployment (Stripe secret key set) refuses every webhook until `STRIPE_WEBHOOK_SECRET` is configured, so an unsigned event can never change the tier. - Automatically upgrades or downgrades the server's `FeatureGate` tier based on authoritative subscription state. - **Zero-Credential Simulation Mode**: - When `STRIPE_SECRET_KEY` is omitted, the engine automatically operates in deterministic simulation mode. - Enables local testing of the complete upgrade/checkout lifecycle without third-party network dependencies. +#### Stripe configuration + +| Variable | Secret | Purpose | +| :--- | :--- | :--- | +| `STRIPE_SECRET_KEY` | Yes | Enables live mode. Unset means simulation mode. | +| `STRIPE_WEBHOOK_SECRET` | Yes | Verifies `Stripe-Signature`. Required in live mode. | +| `STRIPE_PUBLISHABLE_KEY` | No | Returned by the plan endpoint for client use. | +| `STRIPE_PRO_PRICE_ID` | No | Pro price (`price_...`). Pro checkout is off in live mode without it. | +| `STRIPE_ENTERPRISE_PRICE_ID` | No | Optional. Without a real value Enterprise stays contact-sales. | +| `JOLTRIN_PUBLIC_URL` | No | Public origin, builds absolute success and cancel URLs. `STRIPE_SUCCESS_URL` and `STRIPE_CANCEL_URL` override them. | +| `STRIPE_SIMULATE` | No | Forces simulation mode even when a key is present. | + +Each variable also accepts a `JOLTRIN_STRIPE_` prefixed form. The Azure wiring is described in [`infra/azure/README.md`](../infra/azure/README.md). + ### 3. Tamper-Evident Audit Logging ([`governance/audit.go`](../governance/audit.go)) - **`AuditEvent`**: Canonical audit records capturing Actor, Action, Resource, Decision (`allow`, `deny`, `violation`), and Predecessor Hash. - **SHA-256 Hash Chaining**: Every event cryptographically seals the previous event (`PrevHash`), forming a tamper-evident append-only ledger. @@ -77,10 +92,10 @@ The standalone HTTP management server provides integrated plan, billing, and ent | Endpoint | Method | Auth | Description | | :--- | :--- | :--- | :--- | -| `/api/billing/plan` | GET | `withAuth` | Returns active tier, capability matrix, subscription object, and Stripe status. | +| `/api/billing/plan` | GET | `withAuth` | Returns active tier, capability matrix, subscription object, Stripe status, and a `checkout` block showing which tiers can be bought and which environment variables are missing (names only). | | `/api/billing/checkout` | POST | `withAuth` | Creates a Stripe Checkout session (or simulation URL in dev mode). | | `/api/billing/portal` | POST | `withAuth` | Generates a Stripe Customer Portal link to manage cards or subscriptions. | -| `/api/billing/checkout/simulate` | GET | Public | Dev/sandbox callback simulating successful Stripe checkout completion. | +| `/api/billing/checkout/simulate` | GET | Public | Simulation-mode callback that completes a fake checkout. Returns 404 when live Stripe keys are configured. | | `/api/billing/enterprise-contact` | POST | Public | Captures enterprise inquiries (Name, Email, Company, Team Size, Use Cases). | | `/api/billing/webhook` | POST | Public | Ingests Stripe webhook events with HMAC-SHA256 signature verification. | diff --git a/docs/PACKAGES.md b/docs/PACKAGES.md new file mode 100644 index 000000000..5044c2a05 --- /dev/null +++ b/docs/PACKAGES.md @@ -0,0 +1,69 @@ +# Packages and releases + +## Language Packages & Tooling + +| Language | Installation | Description | +| :--- | :--- | :--- | +| **Go** | `go get github.com/sharedcode/joltrin/v5` | Native high-performance core engine. | +| **Python** | `pip install sop4py` | Python bindings with Data Manager and AI scripts. | +| **C#** | `dotnet add package Sop` | Complete .NET Core integration. | +| **WebAssembly** | `GOOS=js GOARCH=wasm go build` | Browser-sandboxed zero-server execution. | +| **HTTP Data Manager** | `sop-httpserver` | Standalone UI console and AI Copilot interface. | +| **Java** *(in progress)* | source in `bindings/java`, not yet on Maven Central | `sop4j` bindings and tests are complete; publishing is blocked on Central Portal credential setup, tracked in [`docs/RELEASE_PROCESS_JAVA_STATUS.md`](RELEASE_PROCESS_JAVA_STATUS.md). | +| **Rust** *(in progress)* | source in `bindings/rust`, not yet on crates.io | `sop4rs` bindings, tests, and examples exist in-repo but are not yet published as a crate. | + +**Naming note:** Joltrin was called SOP until v5. The old names are unchanged so existing code keeps working: the Go package is still `sop`, the published packages are still `sop4py` and `Sop`, the binaries are still `sop-httpserver`, `sop-mcp-server`, `sop-a2a-agent` and `sop-a2a-bridge`, and the default data directory is still `/tmp/sop_data`. + +### How to Consume Joltrin: Releases vs. In-Repo Source + +When integrating Joltrin into your stack, choose between official versioned releases and in-repo source consumption based on your development and operational needs: + +| Dimension | Official Tagged Releases (Recommended for Production) | In-Repo Source / Submodule (Active Prototyping & Contribution) | +| :--- | :--- | :--- | +| **Artifacts** | `go get github.com/sharedcode/joltrin/v5@vX.Y.Z`
PyPI: `pip install sop4py`
NuGet: `dotnet add package Sop` | Git clone or submodule linked directly to `HEAD` or a feature branch | +| **Best For** | Production services, reproducible CI/CD builds, audited dependencies | Modifying engine internals, local benchmarking, custom protocol servers | +| **Stability** | Semantic versioning, tagged releases, audited dependency graph | Bleeding-edge features, experimental branches, unreleased protocol bridges | +| **Maintenance** | Handled by standard language package managers | Requires manual git fetch/rebase and local workspace management | + +#### 1. Official Tagged Releases (Recommended for Production) +For production deployments, pin your dependency to a tagged release. This guarantees reproducible builds, backward-compatible API guarantees, and security-scanned transitive dependencies: +- **Go**: `go get github.com/sharedcode/joltrin/v5@v5.7.0` (see [tags](https://github.com/sharedcode/joltrin/tags) for the latest) +- **Python**: `pip install sop4py==2.3.3` +- **C# / .NET**: `dotnet add package Sop --version 4.5.0` + +#### 2. In-Repo Source / Submodule (Prototyping & Contribution) +If you are extending storage engine internals (`btree/`, `fs/`), modifying protocol servers (`ai/verify`, `cmd/sop-mcp-server`, `cmd/sop-a2a-agent`), or benchmarking performance enhancements, consuming from source is recommended: +```bash +# Add as a git submodule in your project +git submodule add https://github.com/sharedcode/joltrin.git vendor/joltrin + +# Or configure a Go workspace (go.work) for local development +go work use ./vendor/joltrin +``` + +### Cutting a Release (Maintainers) + +Releases are cut from this repo with the scripts in `scripts/`, then tagged and pushed to GitHub. The full step-by-step for building native bindings and publishing to PyPI/NuGet/Maven is in [`RELEASE_PROCESS.md`](../RELEASE_PROCESS.md); the short version: + +```bash +# 1. Bump the version everywhere (VERSION file, go.mod-adjacent metadata, bindings) +./scripts/update_version.sh 5.8.0 + +# 2. Review the diff, then commit the bump +git add -A && git commit -m "bumped version to 5.8.0" + +# 3. Build release artifacts (native libs for Python/Java/C# bindings) +./scripts/build_release.sh + +# 4. Verify checksums, archive integrity, and SBOM before publishing +./scripts/verify_release.sh release + +# 5. Tag and push. This is what makes `go get github.com/sharedcode/joltrin/v5@v5.8.0` resolve. +git tag v5.8.0 +git push origin master v5.8.0 + +# 6. Create the GitHub Release from the tag (attaches release notes + artifacts) +gh release create v5.8.0 --generate-notes +``` + +Go's package proxy needs no separate publish step: once the tag is pushed, `go get ...@v5.8.0` works immediately. Python, C#, and Java bindings still require the explicit `twine upload` / `dotnet nuget push` / `mvn deploy` steps in `RELEASE_PROCESS.md`. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 000000000..8eb2cea93 --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,17 @@ +# Roadmap and platform support + +## Roadmap + +**Shipped and tested today**: the Go core engine, Python bindings (`sop4py`, on PyPI), C# bindings (`Sop`, on NuGet), the WebAssembly browser demo, the standalone HTTP Data Manager, and the interactive AI agent memory checkpointing demo. + +**In progress, code exists in-repo**: Java bindings (`sop4j`), complete with tests, blocked on Maven Central Portal credential setup rather than on missing functionality (see [`docs/RELEASE_PROCESS_JAVA_STATUS.md`](RELEASE_PROCESS_JAVA_STATUS.md)). Rust bindings (`sop4rs`), with tests and examples in-repo, not yet published to crates.io. + +**Proposed, not yet implemented**: the swarm job distribution, `Await`, and `MapReduce` helpers described in [`ai/SWARM_DESIGN.md`](../ai/SWARM_DESIGN.md), which that document itself labels "Proposal / Vision" rather than shipped. + +This list reflects what is actually in the repository at the time of writing. It is not a committed release schedule. + +## Cross-Platform + +CI (`.github/workflows/ci.yml`) builds, vets, and runs the core unit tests (`inmemory`, `btree`, `common`, `cache`, `encoding`, `database`) on `ubuntu-latest`, `macos-latest`, and `windows-latest` on every push and pull request, as three independent, parallel jobs. `macos-latest` runs on Apple Silicon (arm64), so that leg also verifies arm64 for free. + +The Redis- and Cassandra-backed integration and stress test suites stay Linux-only: GitHub Actions' `services:` containers require a Linux-hosted runner, so those specific suites are not run on macOS or Windows today. That is a real gap in what is verified there, not a hidden one. All core unit test packages (`inmemory`, `btree`, `common`, `cache`, `encoding`, `database`) run and pass cleanly across all three operating systems (Linux, macOS, and Windows). diff --git a/docs/STRATEGIC_ARCHITECTURE_AND_MOAT.md b/docs/STRATEGIC_ARCHITECTURE_AND_MOAT.md index 9d78bc227..008950e22 100644 --- a/docs/STRATEGIC_ARCHITECTURE_AND_MOAT.md +++ b/docs/STRATEGIC_ARCHITECTURE_AND_MOAT.md @@ -2,7 +2,7 @@ A candid technical and business assessment of what it would take to move SOP from a working embedded storage engine toward a local-first, enterprise-defensible platform. This document is a **proposal and feasibility review**, not a status report: it says explicitly, section by section, what already exists in this repository today versus what is unbuilt and why. -If you are looking for what SOP has actually proven so far, read [For Investors](../README.md#-for-investors) in the main README first. This document does not repeat that honesty discipline, it extends it into speculative territory, and marks the line between the two clearly throughout. +If you are looking for what SOP has actually proven so far, read [the investor notes](INVESTORS.md) first. This document does not repeat that honesty discipline, it extends it into speculative territory, and marks the line between the two clearly throughout. --- @@ -73,7 +73,7 @@ This is a bounded, well-understood piece of engineering (the Web Crypto API is s The real mechanical claim: if indexing, embedding computation, and query execution happen in the client's browser via Wasm instead of on a server SOP operates, then SOP's marginal infrastructure cost per active user drops, because the expensive part (compute and storage I/O) is no longer something SOP pays for per-user. That's a real, sound argument for *why* gross margins would structurally improve versus a conventional server-side SaaS doing the same work. -**What this document will not do**: state a specific target margin percentage (e.g., "85-90%"), a specific NRR figure, or a specific sales-cycle compression number (e.g., "9 months to weeks"). SOP has no paying customers, no measured COGS, and no sales pipeline today (see the README's own [What Has Not Yet Been Proven](../README.md#-for-investors) section). Any specific percentage in a pitch deck without underlying usage data to support it is a number a diligent investor will ask to see the model behind, and there isn't one yet. The mechanism is real and worth pitching; the number attached to it should come from an actual pilot deployment's actual measured infrastructure spend, not a projection with no data behind it. +**What this document will not do**: state a specific target margin percentage (e.g., "85-90%"), a specific NRR figure, or a specific sales-cycle compression number (e.g., "9 months to weeks"). SOP has no paying customers, no measured COGS, and no sales pipeline today (see the README's own [What Has Not Yet Been Proven](INVESTORS.md) section). Any specific percentage in a pitch deck without underlying usage data to support it is a number a diligent investor will ask to see the model behind, and there isn't one yet. The mechanism is real and worth pitching; the number attached to it should come from an actual pilot deployment's actual measured infrastructure spend, not a projection with no data behind it. ### 3.2 "Why Now" diff --git a/docs/WHO_IS_IT_FOR.md b/docs/WHO_IS_IT_FOR.md new file mode 100644 index 000000000..983163b5e --- /dev/null +++ b/docs/WHO_IS_IT_FOR.md @@ -0,0 +1,52 @@ +# Who Joltrin is for + +### For Potential Customers + +**Is Joltrin Right For Me?** Start from the existing [When Joltrin is a Great Fit](WHY_JOLTRIN.md#when-joltrin-is-a-great-fit) and [When Joltrin is NOT the Right Tool](WHY_JOLTRIN.md#when-joltrin-is-not-the-right-tool) sections above, they are the concrete answer. As a quick filter: + +- If you are currently running Redis plus Postgres plus a queue just to get durable state and coordinated background work for one application, and that application's data fits comfortably on the machines it runs on, Joltrin is worth evaluating as a replacement for that stack. +- If you already run Postgres or Kafka at scale for reasons unrelated to this problem (complex SQL, multi-datacenter event retention, an existing team's expertise), Joltrin is more likely to complement than replace what you have. +- If your workload is petabyte-scale analytics or requires synchronous multi-region consensus, Joltrin is not the right tool today; see the section above for specifics. + +Joltrin is a library you embed, not a managed service you sign up for. There is no hosted offering today; you run it yourself, in-process, in your own infrastructure. + +### For CTOs & Engineering Executives + +Every service you run that exists only to hold state or coordinate work (a cache, a queue, a lock manager) is a service your team has to patch, monitor, upgrade, and page on. Joltrin's bet is that collapsing storage, transactions, and task coordination into one embedded library reduces that surface for the workloads it fits, at the cost of giving up the specialized tooling and operational maturity of dedicated systems your team may already know well. + +Concretely, that means: fewer network hops in your hot path (sub-millisecond, in-process calls instead of 15 to 50ms across Redis, a queue, and Postgres), one dependency to patch and upgrade instead of several, and a transaction boundary that spans your data and your background work instead of stopping at the database. It also means your team takes on a less mature, less battle-tested piece of infrastructure than Postgres or Kafka, with a correspondingly smaller ecosystem, smaller hiring pool of people who already know it, and no enterprise support contract available today. Evaluate it the way you would any early infrastructure bet: pilot it on one bounded, non-critical workload before committing a core system to it. + +### For AI Infrastructure Teams + +**What Joltrin already provides.** Durable, transactional checkpointing for agent reasoning state: each step an agent commits is a separate, durable B-Tree write, so a killed agent process loses nothing already committed, and a successor process can resume from the last checkpoint. This is not a diagram, it runs today in the [browser demo](https://joltrinhq.com/) (the "AI Agent Memory" tab) and as a Go example (`go run ./examples/agent_memory`). Joltrin also provides vector similarity search over embeddings stored in the same B-Tree as structured data (`ai/memory`, `ai/vector`), and a real swarm/worker package (`ai/swarm`) with job and result stores. + +**What could be built on Joltrin, but is not shipped today.** A production multi-agent orchestration framework, a hosted durable-memory-as-a-service for agent frameworks like LangGraph or AutoGen, and distributed MapReduce-style helpers across a live agent swarm are all described as design proposals in [`ai/SWARM_DESIGN.md`](../ai/SWARM_DESIGN.md) (explicitly marked "Proposal / Vision" in that file) but are not implemented and tested the way the checkpointing and vector search primitives are. Treat anything not demonstrated in the linked demo or example as a direction, not a delivered feature. + +**Protocol interoperability, actually implemented.** `tools/mcpserver` and `tools/a2aagent` expose Joltrin runbooks to MCP and A2A clients respectively, both gated by a real safety-and-reachability barrier certificate (`ai/verify`) so a step can't execute out of order regardless of what a calling agent claims. Both protocols share one execution trace store, proven by a test that commits steps via one protocol and confirms the other sees them. See [MCP, A2A, and the Verification Engine](MCP_A2A_AND_VERIFICATION_ENGINE.md) for the audit, the design, and an honest accounting of what this checker is and is not (it is not general-purpose LTL model checking). + +### For Platform, SRE & Cloud Engineers + +Joltrin Engine is a library, not a server: there is no separate database process to provision, patch, or fail over for the embedded case. The optional `tools/httpserver` Data Manager is a standalone service with its own `/metrics` endpoint (tested in `tools/httpserver/metrics_test.go`) if you do want a network-accessible console. Failure recovery is handled by Reed-Solomon erasure coding across storage shards (`fs/erasure`, 12 passing tests at the time of writing) rather than full N-way replication, which trades some recovery latency for lower disk overhead. A prebuilt quickstart container is published to `ghcr.io/sharedcode/joltrin-quickstart`. Multi-node swarm clustering exists and is tested (`examples/swarm_clustered`, `examples/swarm_standalone`), but has not been documented or proven at production scale. + +**Supply-Chain Security & Release Provenance:** Release builds are secured by an automated pre-publish quality gate ([`scripts/verify_release.sh`](../scripts/verify_release.sh)), cryptographic SHA-256 manifests (`SHA256SUMS`), SPDX Software Bill of Materials (SBOM), and cryptographically signed build provenance attestations via GitHub Actions OIDC (`actions/attest-build-provenance`, SLSA Level 3 compliance). Consumers can independently verify any downloaded artifact using the standalone verification script. + +### For Researchers & Distributed Systems Engineers + +The interesting parts to read are the B-Tree implementation with copy-on-write page isolation (`btree/`), the WAL plus two-phase commit transaction protocol (`transaction.go`, `common/`), the Reed-Solomon erasure coding layer (`fs/erasure/`), and the swarm coordination model described in [`ai/SWARM_DESIGN.md`](../ai/SWARM_DESIGN.md). The [Architecture Whitepaper](SOP_ARCHITECTURE_WHITEPAPER.md) and [Architecture vs. Big Tech](ARCHITECTURE_VS_BIG_TECH.md) go deeper into the design tradeoffs than this README does. + +### For Students & Learners + +Reading this codebase is a reasonable way to see real (not textbook-simplified) implementations of a B-Tree with node splitting and range iteration, optimistic concurrency control, write-ahead logging with two-phase commit, and erasure coding, all in readable Go with test coverage next to the implementation. Start with [`docs/WHAT_IS_SOP.md`](WHAT_IS_SOP.md) for a plain-language overview, then run the zero-dependency quickstart below before reading `btree/` and `fs/erasure/`. + +## For Engineering Leaders & Hiring Managers + +For technical leaders, CTOs, and hiring managers, this repository serves as a working demonstration of systems engineering across: + +- **Storage Engine Design**: Custom B-Tree implementation with sector-aligned direct I/O, node slot tuning, and multi-tier L1/L2 caching. +- **Transactional Systems**: Strict ACID guarantees, Write-Ahead Logging (WAL), Two-Phase Commit (2PC), Snapshot Isolation, and Optimistic Concurrency Control. +- **Fault Tolerance & Reliability**: Reed-Solomon Erasure Coding (N+K striping), active/passive metadata redundancy, and automated partition healing. +- **High Concurrency**: Lock-free data structures, multi-goroutine worker swarms, and SIMD vector dot-product calculation. +- **Polyglot Architecture**: Native Go kernel, Python bindings (`sop4py`), C# bindings (`Sop`), and browser WebAssembly. +- **Production Delivery**: GitHub Actions CI/CD matrix, distroless container builds on GHCR, Codecov integration, and static GitHub Pages deployments. + +If you are building distributed systems, cloud infrastructure, or AI data platforms and want to discuss architecture, feel free to connect via [GitHub Discussions](https://github.com/SharedCode/joltrin/discussions). diff --git a/docs/WHY_JOLTRIN.md b/docs/WHY_JOLTRIN.md new file mode 100644 index 000000000..7c52f7a85 --- /dev/null +++ b/docs/WHY_JOLTRIN.md @@ -0,0 +1,109 @@ +# Why Joltrin + +The problem, the approach, an honest comparison, and where Joltrin is not the right tool. + +## What Problem Does Joltrin Solve? + +Most distributed applications require two fundamentally different operations: +1. **Storing state reliably** (databases, key-value stores, vector indexes) +2. **Coordinating work across machines** (task queues, locks, retries, worker failovers) + +Today, developers solve this by assembling a multi-component infrastructure stack: + +``` +THE FRAGMENTED MULTI-COMPONENT STACK (Without Joltrin): + +[ Application ] + โ”‚ + โ”œโ”€โ”€โ–บ (TCP Hop 1: 5-15ms) โ”€โ”€โ–บ Redis (Distributed Locks & Leases) + โ”œโ”€โ”€โ–บ (TCP Hop 2: 5-15ms) โ”€โ”€โ–บ RabbitMQ / Kafka (Task Queue) + โ”œโ”€โ”€โ–บ (TCP Hop 3: 10-30ms) โ”€โ”€โ–บ PostgreSQL / Cassandra (Persistent Storage) + โ””โ”€โ”€โ–บ (Failover Glue) โ”€โ”€โ–บ ZooKeeper / Custom Retry & Outbox Daemons + + 4 infrastructure boundaries | Estimated 15-50ms network latency tax | High split-brain failure risk | High maintenance overhead +``` + +When an application worker crashes between releasing a lock in Redis and committing to PostgreSQL, state can enter an inconsistent split-brain condition. Engineering teams end up spending substantial time writing and maintaining outbox listeners, lock renewers, and compensating retry logic. + +## Why Joltrin? + +Joltrin takes a different approach: **co-locate storage and compute inside the same engine boundary.** + +``` +THE UNIFIED DATA & COMPUTE PLATFORM (With Joltrin): + +[ Application ] + โ”‚ + โ””โ”€โ”€โ–บ (Embedded In-Process Call: < 0.3ms latency) + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ JOLTRIN ENGINE โ”‚ + โ”‚ โ€ข Persistent B-Tree Storage (Sector-aligned Direct I/O) โ”‚ + โ”‚ โ€ข Strict Serializable ACID Transactions (WAL + 2PC) โ”‚ + โ”‚ โ€ข Swarm Compute & Autonomous Task Redistribution โ”‚ + โ”‚ โ€ข High-Dimensional Vector Similarity Indexing (SIMD) โ”‚ + โ”‚ โ€ข Reed-Solomon Erasure Coding & Partition Resilience โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + +โœ“ 1 Single Engine | Sub-millisecond execution | 100% ACID consistency | Automated failover +``` + +Because compute workers, task queues, and storage partitions share the same transaction boundary, a worker failure triggers an automatic rollback of uncommitted work and re-assigns the task in milliseconds with zero orphan locks. + +## Why Now? + +Three industry shifts make this architecture increasingly relevant: + +1. **The Explosion of Autonomous AI Agents**: Multi-agent swarms require frequent context checkpointing, vector similarity searches, and task coordination. Assembling this across Postgres, Pinecone, Redis, and Celery creates high failure surface area. +2. **Edge and Local-First Computing**: Devices in factory automation, vehicles, and retail branches cannot rely on constant connections to central cloud databases. They need full ACID storage and local coordination that works offline. +3. **Infrastructure Simplification**: Engineering organizations are seeking to reduce the operational overhead and cloud bills associated with running dozens of discrete microservices just to manage state and queues. + +## What Makes Joltrin Different? + +Joltrin is built on five core technical principles: + +1. **Embedded Storage Engine**: Operates in-process in Go, Python, and C#, eliminating TCP network hops for local reads and writes. +2. **ACID Transactions without Database Servers**: Implements Write-Ahead Logging (WAL) and Two-Phase Commit (2PC) with copy-on-write page isolation. +3. **Swarm Compute Coordination**: Workers coordinate task execution using storage-anchored sector claims and heartbeat leases without requiring global consensus bottlenecks (like Paxos or Raft) on the hot path. +4. **Reed-Solomon Erasure Coding**: Protects storage shards from hardware failure by striping parity blocks across drives rather than paying the 3x disk storage cost of full replication. +5. **Integrated Vector & Structured Storage**: Stores high-dimensional vector embeddings in the same B-Tree segments as structured metadata, allowing single-transaction memory commits. + +## Joltrin vs. Alternatives + +Every architecture involves tradeoffs. Here is an honest comparison of where Joltrin fits relative to industry standards: + +| Capability | PostgreSQL | Redis | Kafka | Temporal | Pinecone | SQLite | Joltrin | +| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | +| **ACID Transactions** | โœ“ | โ–ณ | โœ— | โœ— | โœ— | โœ“ | โœ“ | +| **Ordered B-Tree Range Scans** | โœ“ | โ–ณ | โœ— | โœ— | โœ— | โœ“ | โœ“ | +| **Embedded In-Process** | โœ— | โœ— | โœ— | โœ— | โœ— | โœ“ | โœ“ | +| **Swarm Work Coordination** | โœ— | โ–ณ | โ–ณ | โœ“ | โœ— | โœ— | โœ“ | +| **Vector Similarity Search** | โ–ณ (pgvector) | โ–ณ | โœ— | โœ— | โœ“ | โœ— | โœ“ | +| **Erasure Coding (N+K)** | โœ— | โœ— | โœ— | โœ— | โœ— | โœ— | โœ“ | +| **Zero Standalone Daemons** | โœ— | โœ— | โœ— | โœ— | โœ— | โœ“ | โœ“ | + +*Legend: `โœ“` First-class native capability | `โ–ณ` Partial or requires plugin/extension | `โœ—` Not designed for this capability* + +### Detailed Tradeoffs by Competitor: + +- **PostgreSQL**: Industry standard for general relational databases. Choose Postgres when you need complex relational schemas, advanced SQL aggregations, or standard ecosystem tooling. Joltrin is better suited when you want an embedded storage engine inside your application process without database server management. +- **Redis**: Industry standard for ultra-low-latency in-memory key-value caching. Choose Redis when all data fits in RAM and you need simple cache operations. Joltrin provides durable B-Tree disk persistence, multi-item ACID transactions, and erasure coding. +- **Kafka / RabbitMQ**: Industry standards for high-volume streaming and pub/sub. Choose Kafka when you need multi-datacenter event streams and log retention. Joltrin provides transactional task queues co-located with storage state for local swarms. +- **NATS (optional, `adapters/nats`)**: not a replacement for anything joltrin embeds, and not on the hot path. If a team already runs NATS as part of their own architecture, `adapters/nats.VerifyBridge` will publish `ai/verify` barrier decisions to it, fire-and-forget, after the decision is already made, so another service outside joltrin's process can observe it without polling. Nothing imports this by default and a publish failure can never change the barrier's own answer. See the addendum in `docs/MCP_A2A_AND_VERIFICATION_ENGINE.md` for the full reasoning on why this doesn't reverse the embedded design. +- **Temporal**: Industry standard for long-running durable workflows spanning external microservices. Choose Temporal for multi-week human-in-the-loop workflows across disparate clouds. Joltrin is designed for local-to-cluster co-located data and task execution. +- **SQLite**: Industry standard for embedded single-file relational databases. Choose SQLite for client desktop/mobile apps needing SQL. Joltrin is designed for high-concurrency multi-threaded workers, clustered coordination, partitioned vector stores, and erasure coding. + +## When Joltrin Is a Great Fit + +- **AI Agent Memory & Swarm Workforces**: Autonomous agents requiring durable conversation memory, vector similarity search, and task hand-offs without fragmented external databases. Checkpoints commit directly to B-Tree segments with atomic rollback if a worker crashes mid-reasoning. +- **Real-Time Systems & Simulation State**: Game servers, robotics, and spatial computing needing sub-millisecond in-process transactional serialization (measured at 100k-145k ops/sec in local benchmarks) without database network hops. +- **Financial & Escrow Ledgers**: Systems requiring snapshot isolation, optimistic concurrency control (OCC), two-phase commit (2PC), and invariant verification (such as validating zero-sum account deltas before commit). +- **Edge & IoT Computing**: Devices operating in local or intermittent network environments that need local embedded ACID persistence, with experimental peer coordination. +- **Serverless Workloads**: Cloud functions and containers that need durable storage without exhausting external database connection pools. + +## When Joltrin is NOT the Right Tool + +To be completely clear on architectural boundaries: + +- **Massive Analytical Warehousing**: If you are running multi-petabyte columnar analytics across billions of historical events, specialized OLAP warehouses (like ClickHouse or Snowflake) are the right choice. +- **Global Multi-Region Consensus**: If your application requires synchronous commits across continents with multi-region Raft/Paxos quorums, dedicated distributed SQL databases (like CockroachDB or Google Spanner) are designed for that problem. +- **Simple Stateless CRUD Apps**: If your application is a standard CRUD dashboard with low traffic, standard PostgreSQL or MySQL with an ORM is simpler and has more ecosystem plugins. diff --git a/governance/billing.go b/governance/billing.go index 3412f251e..e10bb129d 100644 --- a/governance/billing.go +++ b/governance/billing.go @@ -27,6 +27,16 @@ var ( ErrDuplicateWebhookEvent = errors.New("governance/billing: duplicate webhook event already processed") ErrInvalidPriceOrTier = errors.New("governance/billing: unrecognized pricing plan or target tier") ErrBillingNotConfigured = errors.New("governance/billing: Stripe credentials not configured") + ErrEnterpriseContactSales = errors.New("governance/billing: Enterprise is contact-sales only, no Enterprise price is configured") + ErrWebhookNotConfigured = errors.New("governance/billing: webhook signing secret is not configured") +) + +// Placeholder price IDs the service falls back to when none is configured. +// They are never valid Stripe prices, so a live deployment that still holds +// one must not offer checkout for that tier. +const ( + placeholderProPriceID = "price_joltrin_pro_monthly" + placeholderEnterprisePriceID = "price_joltrin_enterprise_annual" ) // SubscriptionStatus represents the lifecycle state of a commercial license subscription. @@ -98,6 +108,88 @@ type StripeConfig struct { Simulate bool `json:"simulate"` } +// TierCheckout describes whether a tier can be bought through checkout. +// Mode is one of "stripe", "simulated", "contact_sales", or "unavailable". +// Missing lists environment variable names only, never values. +type TierCheckout struct { + Available bool `json:"available"` + Mode string `json:"mode"` + Missing []string `json:"missing,omitempty"` +} + +// BillingReadiness is a secret-free summary of what the current Stripe +// configuration can actually do, so an operator can see why checkout is off +// without reading logs or the Key Vault. +type BillingReadiness struct { + Mode string `json:"mode"` // "live" or "simulated" + Pro TierCheckout `json:"pro"` + Enterprise TierCheckout `json:"enterprise"` +} + +func isAbsoluteURL(u string) bool { + return strings.HasPrefix(u, "https://") || strings.HasPrefix(u, "http://") +} + +// AssessBilling reports which tiers can complete checkout with cfg. Live +// checkout needs a real price, a webhook signing secret (otherwise a paid +// customer would never be upgraded), and absolute return URLs. Enterprise +// stays contact-sales until a real Enterprise price ID is configured. +func AssessBilling(cfg StripeConfig) BillingReadiness { + live := cfg.SecretKey != "" && !cfg.Simulate + + hasPro := cfg.ProPriceID != "" && cfg.ProPriceID != placeholderProPriceID + hasEnt := cfg.EnterprisePriceID != "" && cfg.EnterprisePriceID != placeholderEnterprisePriceID + + r := BillingReadiness{Mode: "simulated"} + if live { + r.Mode = "live" + } + + switch { + case !live: + r.Pro = TierCheckout{Available: true, Mode: "simulated"} + default: + var missing []string + if !hasPro { + missing = append(missing, "STRIPE_PRO_PRICE_ID") + } + if cfg.WebhookSecret == "" { + missing = append(missing, "STRIPE_WEBHOOK_SECRET") + } + if !isAbsoluteURL(cfg.SuccessURL) { + missing = append(missing, "STRIPE_SUCCESS_URL") + } + if !isAbsoluteURL(cfg.CancelURL) { + missing = append(missing, "STRIPE_CANCEL_URL") + } + if len(missing) == 0 { + r.Pro = TierCheckout{Available: true, Mode: "stripe"} + } else { + r.Pro = TierCheckout{Mode: "unavailable", Missing: missing} + } + } + + if !hasEnt { + r.Enterprise = TierCheckout{Mode: "contact_sales"} + } else if !live { + r.Enterprise = TierCheckout{Available: true, Mode: "simulated"} + } else { + r.Enterprise = r.Pro + r.Enterprise.Missing = nil + for _, m := range r.Pro.Missing { + if m != "STRIPE_PRO_PRICE_ID" { + r.Enterprise.Missing = append(r.Enterprise.Missing, m) + } + } + if len(r.Enterprise.Missing) == 0 { + r.Enterprise.Available, r.Enterprise.Mode = true, "stripe" + } else { + r.Enterprise.Available, r.Enterprise.Mode = false, "unavailable" + } + } + return r +} + // VerifyStripeSignature cryptographically verifies a Stripe-Signature header using HMAC-SHA256. func VerifyStripeSignature(payload []byte, sigHeader string, secret string, tolerance time.Duration) error { if secret == "" { @@ -216,10 +308,10 @@ type DefaultBillingService struct { // in-memory-only behavior. func NewDefaultBillingService(cfg StripeConfig, gate *FeatureGate, store ...BillingStore) *DefaultBillingService { if cfg.ProPriceID == "" { - cfg.ProPriceID = "price_joltrin_pro_monthly" + cfg.ProPriceID = placeholderProPriceID } if cfg.EnterprisePriceID == "" { - cfg.EnterprisePriceID = "price_joltrin_enterprise_annual" + cfg.EnterprisePriceID = placeholderEnterprisePriceID } if cfg.SecretKey == "" { cfg.Simulate = true @@ -339,11 +431,25 @@ func (s *DefaultBillingService) CreateCheckoutSession(ctx context.Context, tenan case TierPro: priceID = s.cfg.ProPriceID case TierEnterprise: + if s.cfg.EnterprisePriceID == placeholderEnterprisePriceID { + return nil, ErrEnterpriseContactSales + } priceID = s.cfg.EnterprisePriceID default: return nil, fmt.Errorf("%w: %s", ErrInvalidPriceOrTier, tier) } + if !s.cfg.Simulate && s.cfg.SecretKey != "" { + readiness := AssessBilling(s.cfg) + tc := readiness.Pro + if tier == TierEnterprise { + tc = readiness.Enterprise + } + if !tc.Available { + return nil, fmt.Errorf("%w: missing %s", ErrBillingNotConfigured, strings.Join(tc.Missing, ", ")) + } + } + // Simulation mode when no live Stripe secret key is present if s.cfg.Simulate || s.cfg.SecretKey == "" { sessionID := "cs_sim_" + uuid.NewString()[:8] @@ -379,11 +485,11 @@ func (s *DefaultBillingService) CreateCheckoutSession(ctx context.Context, tenan successURL := s.cfg.SuccessURL if successURL == "" { - successURL = "https://joltrin.com/app?checkout=success&session_id={CHECKOUT_SESSION_ID}" + successURL = "https://joltrinhq.com/app?checkout=success&session_id={CHECKOUT_SESSION_ID}" } cancelURL := s.cfg.CancelURL if cancelURL == "" { - cancelURL = "https://joltrin.com/app?checkout=canceled" + cancelURL = "https://joltrinhq.com/app?checkout=canceled" } data.Set("success_url", successURL) data.Set("cancel_url", cancelURL) @@ -451,7 +557,12 @@ func (s *DefaultBillingService) CreatePortalSession(ctx context.Context, custome // HandleWebhook processes incoming Stripe webhook events idempotently and verifies HMAC signatures. func (s *DefaultBillingService) HandleWebhook(ctx context.Context, payload []byte, sigHeader string) (*StripeWebhookEvent, error) { - // 1. Signature Verification + // 1. Signature Verification. A live deployment must never accept an + // unsigned event: without a signing secret anyone could post a forged + // checkout.session.completed and upgrade the server's tier. + if s.cfg.WebhookSecret == "" && !s.cfg.Simulate && s.cfg.SecretKey != "" { + return nil, ErrWebhookNotConfigured + } if s.cfg.WebhookSecret != "" { if err := VerifyStripeSignature(payload, sigHeader, s.cfg.WebhookSecret, 300*time.Second); err != nil { return nil, err diff --git a/governance/billing_readiness_test.go b/governance/billing_readiness_test.go new file mode 100644 index 000000000..c48aab62f --- /dev/null +++ b/governance/billing_readiness_test.go @@ -0,0 +1,209 @@ +package governance + +import ( + "context" + "encoding/json" + "errors" + "strings" + "testing" + "time" +) + +func liveConfig() StripeConfig { + return StripeConfig{ + SecretKey: "sk_test_placeholder", + WebhookSecret: "whsec_placeholder", + ProPriceID: "price_pro_real", + SuccessURL: "https://example.test/app?checkout=success", + CancelURL: "https://example.test/app?checkout=canceled", + } +} + +func TestAssessBilling_SimulationMode(t *testing.T) { + r := AssessBilling(StripeConfig{}) + if r.Mode != "simulated" || !r.Pro.Available || r.Pro.Mode != "simulated" { + t.Fatalf("expected simulated Pro checkout, got %+v", r) + } + if r.Enterprise.Available || r.Enterprise.Mode != "contact_sales" { + t.Fatalf("Enterprise must stay contact-sales without a price ID, got %+v", r.Enterprise) + } +} + +func TestAssessBilling_LiveMissingConfigNamesVariablesOnly(t *testing.T) { + r := AssessBilling(StripeConfig{SecretKey: "sk_test_placeholder", ProPriceID: placeholderProPriceID}) + if r.Mode != "live" || r.Pro.Available { + t.Fatalf("live mode with missing config must not offer checkout, got %+v", r.Pro) + } + want := map[string]bool{ + "STRIPE_PRO_PRICE_ID": true, + "STRIPE_WEBHOOK_SECRET": true, + "STRIPE_SUCCESS_URL": true, + "STRIPE_CANCEL_URL": true, + } + for _, m := range r.Pro.Missing { + if !want[m] { + t.Errorf("unexpected missing entry %q", m) + } + delete(want, m) + } + if len(want) != 0 { + t.Errorf("missing entries not reported: %v", want) + } + raw, _ := json.Marshal(r) + if strings.Contains(string(raw), "sk_test_placeholder") { + t.Error("readiness output must not contain the secret key") + } +} + +func TestAssessBilling_LiveFullyConfigured(t *testing.T) { + r := AssessBilling(liveConfig()) + if !r.Pro.Available || r.Pro.Mode != "stripe" { + t.Fatalf("expected live Pro checkout, got %+v", r.Pro) + } + if r.Enterprise.Available || r.Enterprise.Mode != "contact_sales" { + t.Fatalf("Enterprise stays contact-sales without its own price, got %+v", r.Enterprise) + } + + cfg := liveConfig() + cfg.EnterprisePriceID = "price_ent_real" + r = AssessBilling(cfg) + if !r.Enterprise.Available || r.Enterprise.Mode != "stripe" { + t.Fatalf("a real Enterprise price ID should enable Enterprise checkout, got %+v", r.Enterprise) + } +} + +func TestCreateCheckoutSession_EnterpriseIsContactSalesWithoutPrice(t *testing.T) { + for _, cfg := range []StripeConfig{{Simulate: true}, liveConfig()} { + svc := NewDefaultBillingService(cfg, NewFeatureGate(TierCore)) + _, err := svc.CreateCheckoutSession(context.Background(), "t1", "a@example.com", TierEnterprise) + if !errors.Is(err, ErrEnterpriseContactSales) { + t.Errorf("simulate=%v: expected ErrEnterpriseContactSales, got %v", cfg.Simulate, err) + } + } +} + +func TestCreateCheckoutSession_LiveWithoutPriceIDIsRefused(t *testing.T) { + cfg := liveConfig() + cfg.ProPriceID = "" + svc := NewDefaultBillingService(cfg, NewFeatureGate(TierCore)) + _, err := svc.CreateCheckoutSession(context.Background(), "t1", "a@example.com", TierPro) + if !errors.Is(err, ErrBillingNotConfigured) { + t.Fatalf("expected ErrBillingNotConfigured, got %v", err) + } +} + +func TestHandleWebhook_LiveWithoutSigningSecretIsRefused(t *testing.T) { + gate := NewFeatureGate(TierCore) + svc := NewDefaultBillingService(StripeConfig{SecretKey: "sk_test_placeholder", ProPriceID: "price_pro_real"}, gate) + + payload := ConstructSimulatedWebhookPayload("checkout.session.completed", "evt_unsigned_live", "t1", TierPro) + _, err := svc.HandleWebhook(context.Background(), payload, "") + if !errors.Is(err, ErrWebhookNotConfigured) { + t.Fatalf("expected ErrWebhookNotConfigured, got %v", err) + } + if gate.Tier() != TierCore { + t.Fatalf("a refused webhook must not change the tier, got %s", gate.Tier()) + } +} + +func TestHandleWebhook_LiveRejectsMissingAndWrongSignature(t *testing.T) { + gate := NewFeatureGate(TierCore) + svc := NewDefaultBillingService(liveConfig(), gate) + payload := ConstructSimulatedWebhookPayload("checkout.session.completed", "evt_bad_sig", "t1", TierPro) + + if _, err := svc.HandleWebhook(context.Background(), payload, ""); !errors.Is(err, ErrInvalidWebhookSignature) { + t.Errorf("missing signature: expected ErrInvalidWebhookSignature, got %v", err) + } + wrong := GenerateStripeSignatureHeader(payload, "whsec_some_other_secret", time.Now()) + if _, err := svc.HandleWebhook(context.Background(), payload, wrong); !errors.Is(err, ErrInvalidWebhookSignature) { + t.Errorf("wrong secret: expected ErrInvalidWebhookSignature, got %v", err) + } + if gate.Tier() != TierCore { + t.Fatalf("rejected events must not change the tier, got %s", gate.Tier()) + } +} + +func deliver(t *testing.T, svc *DefaultBillingService, secret, id, typ string, obj map[string]any) { + t.Helper() + payload, _ := json.Marshal(map[string]any{ + "id": id, + "type": typ, + "created": time.Now().Unix(), + "data": map[string]any{"object": obj}, + }) + sig := GenerateStripeSignatureHeader(payload, secret, time.Now()) + if _, err := svc.HandleWebhook(context.Background(), payload, sig); err != nil { + t.Fatalf("%s: %v", typ, err) + } +} + +func TestSubscriptionLifecycle_PaymentFailureRecoveryAndCancellation(t *testing.T) { + cfg := liveConfig() + gate := NewFeatureGate(TierCore) + svc := NewDefaultBillingService(cfg, gate, NewJoltrinBillingStore(t.TempDir())) + secret := cfg.WebhookSecret + ctx := context.Background() + + status := func() SubscriptionStatus { + sub, _ := svc.GetSubscription(ctx, "t-life") + return sub.Status + } + + deliver(t, svc, secret, "evt_life_1", "checkout.session.completed", map[string]any{ + "client_reference_id": "t-life", + "customer": "cus_life", + "subscription": "sub_life", + "metadata": map[string]any{"tier": "pro"}, + }) + if gate.Tier() != TierPro || status() != SubStatusActive { + t.Fatalf("after checkout: tier=%s status=%s", gate.Tier(), status()) + } + + deliver(t, svc, secret, "evt_life_2", "invoice.payment_failed", map[string]any{"customer": "cus_life"}) + if status() != SubStatusPastDue { + t.Fatalf("after payment failure: status=%s", status()) + } + + deliver(t, svc, secret, "evt_life_3", "invoice.payment_succeeded", map[string]any{"customer": "cus_life"}) + if status() != SubStatusActive || gate.Tier() != TierPro { + t.Fatalf("after recovery: tier=%s status=%s", gate.Tier(), status()) + } + + deliver(t, svc, secret, "evt_life_4", "customer.subscription.updated", map[string]any{ + "id": "sub_life", "customer": "cus_life", "status": "canceled", + "metadata": map[string]any{"tier": "pro"}, + }) + if status() != SubStatusCanceled || gate.Tier() != TierCore { + t.Fatalf("after cancel update: tier=%s status=%s", gate.Tier(), status()) + } +} + +func TestSubscriptionLifecycle_DeletedEventSurvivesRestart(t *testing.T) { + cfg := liveConfig() + dir := t.TempDir() + svc := NewDefaultBillingService(cfg, NewFeatureGate(TierCore), NewJoltrinBillingStore(dir)) + + deliver(t, svc, cfg.WebhookSecret, "evt_restart_1", "checkout.session.completed", map[string]any{ + "client_reference_id": "t-restart", "customer": "cus_restart", "subscription": "sub_restart", + }) + deliver(t, svc, cfg.WebhookSecret, "evt_restart_2", "customer.subscription.deleted", map[string]any{ + "customer": "cus_restart", + }) + + gate2 := NewFeatureGate(TierCore) + svc2 := NewDefaultBillingService(cfg, gate2, NewJoltrinBillingStore(dir)) + sub, _ := svc2.GetSubscription(context.Background(), "t-restart") + if sub.Status != SubStatusCanceled { + t.Fatalf("canceled status must persist across restart, got %s", sub.Status) + } + + // A redelivered event after restart is still treated as a duplicate. + payload, _ := json.Marshal(map[string]any{ + "id": "evt_restart_2", "type": "customer.subscription.deleted", "created": time.Now().Unix(), + "data": map[string]any{"object": map[string]any{"customer": "cus_restart"}}, + }) + sig := GenerateStripeSignatureHeader(payload, cfg.WebhookSecret, time.Now()) + if _, err := svc2.HandleWebhook(context.Background(), payload, sig); !errors.Is(err, ErrDuplicateWebhookEvent) { + t.Fatalf("expected duplicate after restart, got %v", err) + } +} diff --git a/infra/azure/README.md b/infra/azure/README.md index 570f9829e..febc908c5 100644 --- a/infra/azure/README.md +++ b/infra/azure/README.md @@ -48,6 +48,31 @@ az deployment group create \ -p stripeWebhookSecret= ``` +Stripe values, and which ones are secret: + +| Value | Where it goes | Secret | +| :--- | :--- | :--- | +| `stripeSecretKey`, `stripeWebhookSecret` | Key Vault, injected as secret references | Yes | +| `stripePublishableKey` | Key Vault | No | +| `stripeProPriceId`, `stripeEnterprisePriceId` | Plain env vars (`STRIPE_PRO_PRICE_ID`, `STRIPE_ENTERPRISE_PRICE_ID`) | No | +| `publicBaseUrl` | Plain env var (`JOLTRIN_PUBLIC_URL`), builds the absolute success and cancel URLs | No | + +Every Stripe value defaults to empty. An empty secret is stored in Key Vault as the +literal `unset` (Key Vault rejects empty values) and the server treats it as empty, +so an unconfigured deployment stays in simulation mode. Pro checkout turns on only +when the secret key, webhook secret, Pro price ID, and public URL are all present. +Enterprise stays contact-sales until `stripeEnterprisePriceId` is a real price. + +`GET /api/billing/plan` returns a `checkout` block that names any missing variable +(names only, never values), so you can see why checkout is off without reading logs. + +`deploy-azure.yml` passes these from repository secrets (`STRIPE_SECRET_KEY`, +`STRIPE_WEBHOOK_SECRET`) and repository variables (`STRIPE_PUBLISHABLE_KEY`, +`STRIPE_PRO_PRICE_ID`, `STRIPE_ENTERPRISE_PRICE_ID`, `JOLTRIN_PUBLIC_URL`). Set the +secrets in GitHub rather than writing them to Key Vault by hand: every deploy +re-applies the Key Vault secrets from the workflow inputs and would overwrite a +value set manually. + The first deploy provisions the ACR before an image exists in it; build and push the image, then re-run `az deployment group create` with the resulting `containerImage` value (this is exactly what `deploy-azure.yml` automates). diff --git a/infra/azure/main.bicep b/infra/azure/main.bicep index d0999f9ae..3e080968b 100644 --- a/infra/azure/main.bicep +++ b/infra/azure/main.bicep @@ -36,15 +36,24 @@ param monthlyBudgetUsd int = 25 @secure() @description('Stripe secret key. Stored in Key Vault, never in source control or plain env vars.') -param stripeSecretKey string +param stripeSecretKey string = '' @secure() @description('Stripe webhook signing secret.') -param stripeWebhookSecret string +param stripeWebhookSecret string = '' @description('Stripe publishable key (not secret, but kept alongside the others for consistency).') param stripePublishableKey string = '' +@description('Stripe Price ID for the Pro plan (price_...). Not secret. Leave empty until the product exists in Stripe; Pro checkout stays off while it is empty.') +param stripeProPriceId string = '' + +@description('Stripe Price ID for the Enterprise plan. Leave empty to keep Enterprise contact-sales.') +param stripeEnterprisePriceId string = '' + +@description('Public origin of the deployed app, e.g. https://app.example.com (no trailing slash). Used to build the absolute Stripe success and cancel URLs.') +param publicBaseUrl string = '' + var resourceToken = uniqueString(resourceGroup().id, appName) var logAnalyticsName = '${appName}-logs-${resourceToken}' var acrName = replace('${appName}acr${resourceToken}', '-', '') @@ -113,6 +122,9 @@ module containerApp 'modules/container-app.bicep' = { userAssignedIdentityId: identity.outputs.id userAssignedIdentityClientId: identity.outputs.clientId keyVaultUri: keyVault.outputs.uri + stripeProPriceId: stripeProPriceId + stripeEnterprisePriceId: stripeEnterprisePriceId + publicBaseUrl: publicBaseUrl } } diff --git a/infra/azure/main.parameters.json b/infra/azure/main.parameters.json index 5ca76dbec..4c7f004a3 100644 --- a/infra/azure/main.parameters.json +++ b/infra/azure/main.parameters.json @@ -19,6 +19,15 @@ }, "stripePublishableKey": { "value": "" + }, + "stripeProPriceId": { + "value": "" + }, + "stripeEnterprisePriceId": { + "value": "" + }, + "publicBaseUrl": { + "value": "" } } } diff --git a/infra/azure/modules/container-app.bicep b/infra/azure/modules/container-app.bicep index 89b1933c5..ebdeb1765 100644 --- a/infra/azure/modules/container-app.bicep +++ b/infra/azure/modules/container-app.bicep @@ -14,6 +14,34 @@ param userAssignedIdentityId string param userAssignedIdentityClientId string param keyVaultUri string +@description('Stripe Price IDs are identifiers, not secrets, so they are plain env vars. Empty means the plan is not purchasable through checkout.') +param stripeProPriceId string = '' +param stripeEnterprisePriceId string = '' + +@description('Public origin of the app (no trailing slash), used for absolute Stripe return URLs.') +param publicBaseUrl string = '' + +var optionalEnv = concat( + empty(stripeProPriceId) ? [] : [ + { + name: 'STRIPE_PRO_PRICE_ID' + value: stripeProPriceId + } + ], + empty(stripeEnterprisePriceId) ? [] : [ + { + name: 'STRIPE_ENTERPRISE_PRICE_ID' + value: stripeEnterprisePriceId + } + ], + empty(publicBaseUrl) ? [] : [ + { + name: 'JOLTRIN_PUBLIC_URL' + value: publicBaseUrl + } + ] +) + // Pinned to 1 replica: joltrin's embedded B-Tree engine has no documented // multi-process write-safety guarantee, and this deployment optimizes for // lowest cost over horizontal scale. CPU/memory/concurrency limits below @@ -84,7 +112,7 @@ resource containerApp 'Microsoft.App/containerApps@2023-11-02-preview' = { '8080' '-open-browser=false' ] - env: [ + env: concat([ { name: 'STRIPE_SECRET_KEY' secretRef: 'stripe-secret-key' @@ -101,7 +129,7 @@ resource containerApp 'Microsoft.App/containerApps@2023-11-02-preview' = { name: 'AZURE_CLIENT_ID' value: userAssignedIdentityClientId } - ] + ], optionalEnv) // 0.5 vCPU / 1.0 GiB: matches the requested cost-containment // sizing. Combined GB-CPU pairing is one of ACA's valid // combinations (0.5 vCPU pairs with 1Gi). diff --git a/infra/azure/modules/key-vault.bicep b/infra/azure/modules/key-vault.bicep index dc45538bb..50b3b43bd 100644 --- a/infra/azure/modules/key-vault.bicep +++ b/infra/azure/modules/key-vault.bicep @@ -46,7 +46,7 @@ resource secretStripeKey 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { parent: vault name: 'stripe-secret-key' properties: { - value: stripeSecretKey + value: empty(stripeSecretKey) ? 'unset' : stripeSecretKey } } @@ -54,7 +54,7 @@ resource secretWebhookSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { parent: vault name: 'stripe-webhook-secret' properties: { - value: stripeWebhookSecret + value: empty(stripeWebhookSecret) ? 'unset' : stripeWebhookSecret } } diff --git a/scripts/build-site.sh b/scripts/build-site.sh index 37c3dd1f2..094ee59b0 100755 --- a/scripts/build-site.sh +++ b/scripts/build-site.sh @@ -44,7 +44,7 @@ echo "Copying Documentation and Assets..." cp -r docs/. _site/docs/ cp -r docs/assets/. _site/assets/ -# Preserve custom domain (e.g. joltrin.com) if CNAME exists +# Preserve custom domain (e.g. joltrinhq.com) if CNAME exists if [ -f "CNAME" ]; then cp CNAME _site/CNAME elif [ -f "demo/CNAME" ]; then diff --git a/sop-arena/index.html b/sop-arena/index.html index e10e2ad94..3c7e2bc5e 100644 --- a/sop-arena/index.html +++ b/sop-arena/index.html @@ -11,21 +11,21 @@ - + - + - + - + - + diff --git a/tests/homepage.spec.ts b/tests/homepage.spec.ts new file mode 100644 index 000000000..93fcb0211 --- /dev/null +++ b/tests/homepage.spec.ts @@ -0,0 +1,73 @@ +import { test, expect } from '@playwright/test'; +import { waitForWasmReady } from './helpers/wasm-lifecycle'; + +/** + * Homepage positioning, pricing honesty, and metadata. + * Covers the simplified hero, the three live experiences, the open-core + * plans, the Pro request flow on a static host, and the domain in metadata. + */ +test.describe('Homepage', () => { + test('hero states the product and offers one primary action', async ({ page }) => { + await page.goto('/', { waitUntil: 'domcontentloaded' }); + await expect(page.getByRole('heading', { level: 1 })).toContainText(/durable memory/i); + await expect(page.getByRole('heading', { level: 1 })).toContainText(/verification barrier/i); + await expect(page.getByRole('link', { name: /start building/i }).first()).toBeVisible(); + await expect(page.getByRole('link', { name: /try the live barrier/i })).toHaveAttribute('href', /agents/); + }); + + test('three live experiences are linked right after the hero', async ({ page }) => { + await page.goto('/', { waitUntil: 'domcontentloaded' }); + const strip = page.locator('#live-experiences'); + await expect(strip.locator('a')).toHaveCount(3); + await expect(strip.locator('a[href="#under-the-hood"]')).toBeVisible(); + await expect(strip.locator('a[href="./arena/"]')).toBeVisible(); + await expect(strip.locator('a[href="./agents/"]')).toBeVisible(); + }); + + test('pricing shows open source, Pro, and Enterprise contact without live-checkout claims', async ({ page }) => { + await page.goto('/', { waitUntil: 'domcontentloaded' }); + const pricing = page.locator('#pricing'); + await expect(pricing).toContainText('$0'); + await expect(pricing).toContainText('$49'); + await expect(pricing.getByRole('button', { name: /talk to us/i })).toBeVisible(); + await expect(pricing.getByRole('button', { name: /request pro/i })).toBeVisible(); + const text = (await pricing.innerText()).toLowerCase(); + for (const claim of ['instant workspace', 'apple pay', 'google pay', 'automated stripe', 'most popular']) { + expect(text, `pricing must not say "${claim}"`).not.toContain(claim); + } + }); + + test('requesting Pro on the static host falls back to email instead of faking checkout', async ({ page }) => { + await page.goto('/', { waitUntil: 'domcontentloaded' }); + await waitForWasmReady(page); + await page.locator('#pricing').getByRole('button', { name: /request pro/i }).click(); + const modal = page.locator('#pro-checkout-modal'); + await expect(modal).toBeVisible(); + await expect(modal).not.toContainText(/annual|\$490/i); + await page.fill('#pro-team-name', 'example-team'); + await page.fill('#pro-admin-email', 'admin@example.test'); + await modal.getByRole('button', { name: /^request pro$/i }).click(); + await expect(page.locator('#pro-checkout-status')).toContainText(/isn't available on this site yet/i, { timeout: 10_000 }); + await expect(page.locator('#pro-checkout-status a[href^="mailto:"]')).toBeVisible(); + }); + + test('canonical and social metadata point at joltrinhq.com on all three pages', async ({ request }) => { + for (const [path, expected] of [ + ['/', 'https://joltrinhq.com/'], + ['/agents/', 'https://joltrinhq.com/agents/'], + ['/arena/', 'https://joltrinhq.com/arena/'], + ]) { + const html = await (await request.get(path)).text(); + expect(html, path).toContain(` { + await page.goto('/', { waitUntil: 'domcontentloaded' }); + await waitForWasmReady(page); + const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth); + expect(overflow).toBeLessThanOrEqual(0); + }); +}); diff --git a/tools/httpserver/billing_handler.go b/tools/httpserver/billing_handler.go index 8cb22a0d9..81bc4ac3f 100644 --- a/tools/httpserver/billing_handler.go +++ b/tools/httpserver/billing_handler.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "errors" "fmt" "io" "net/http" @@ -9,6 +10,7 @@ import ( "path/filepath" "strings" "sync" + "time" "github.com/sharedcode/joltrin/v5/governance" ) @@ -67,27 +69,61 @@ func checkBillingRateLimit(w http.ResponseWriter, r *http.Request) bool { return true } +// loadStripeConfig reads Stripe settings through getenv so tests can supply +// their own environment. Each setting also accepts a JOLTRIN_STRIPE_* form. +// +// The Azure deployment stores the literal "unset" in Key Vault for a Stripe +// secret that has not been provided yet (Key Vault rejects empty values). +// That placeholder is treated as empty, so an unconfigured deployment stays in +// simulation mode instead of trying to use "unset" as a key. +func loadStripeConfig(getenv func(string) string) governance.StripeConfig { + getenv = ignoreUnset(getenv) + secretKey := firstNonEmpty(getenv("STRIPE_SECRET_KEY"), getenv("JOLTRIN_STRIPE_SECRET_KEY")) + webhookSecret := firstNonEmpty(getenv("STRIPE_WEBHOOK_SECRET"), getenv("JOLTRIN_STRIPE_WEBHOOK_SECRET")) + publishableKey := firstNonEmpty(getenv("STRIPE_PUBLISHABLE_KEY"), getenv("JOLTRIN_STRIPE_PUBLISHABLE_KEY")) + proPriceID := firstNonEmpty(getenv("STRIPE_PRO_PRICE_ID"), getenv("JOLTRIN_STRIPE_PRO_PRICE_ID")) + entPriceID := firstNonEmpty(getenv("STRIPE_ENTERPRISE_PRICE_ID"), getenv("JOLTRIN_STRIPE_ENTERPRISE_PRICE_ID")) + simulateStr := strings.ToLower(getenv("STRIPE_SIMULATE")) + simulate := simulateStr == "true" || simulateStr == "1" || secretKey == "" + + // Stripe requires absolute return URLs. JOLTRIN_PUBLIC_URL (the + // site's public origin, no trailing slash) builds them; without it + // the relative defaults only work in simulation mode and billing + // readiness reports the URL variables as missing. + successDefault, cancelDefault := "/app?checkout=success", "/app?checkout=canceled" + if base := strings.TrimRight(getenv("JOLTRIN_PUBLIC_URL"), "/"); base != "" { + successDefault = base + "/app?checkout=success&session_id={CHECKOUT_SESSION_ID}" + cancelDefault = base + "/app?checkout=canceled" + } + + return governance.StripeConfig{ + SecretKey: secretKey, + WebhookSecret: webhookSecret, + PublishableKey: publishableKey, + ProPriceID: proPriceID, + EnterprisePriceID: entPriceID, + SuccessURL: firstNonEmpty(getenv("STRIPE_SUCCESS_URL"), successDefault), + CancelURL: firstNonEmpty(getenv("STRIPE_CANCEL_URL"), cancelDefault), + Simulate: simulate, + } +} + +func ignoreUnset(getenv func(string) string) func(string) string { + return func(k string) string { + if v := getenv(k); v != "unset" { + return v + } + return "" + } +} + func getBillingService() governance.BillingService { billingServiceOnce.Do(func() { gate := getServerFeatureGate() - secretKey := firstNonEmpty(os.Getenv("STRIPE_SECRET_KEY"), os.Getenv("JOLTRIN_STRIPE_SECRET_KEY")) - webhookSecret := firstNonEmpty(os.Getenv("STRIPE_WEBHOOK_SECRET"), os.Getenv("JOLTRIN_STRIPE_WEBHOOK_SECRET")) - publishableKey := firstNonEmpty(os.Getenv("STRIPE_PUBLISHABLE_KEY"), os.Getenv("JOLTRIN_STRIPE_PUBLISHABLE_KEY")) - proPriceID := firstNonEmpty(os.Getenv("STRIPE_PRO_PRICE_ID"), os.Getenv("JOLTRIN_STRIPE_PRO_PRICE_ID")) - entPriceID := firstNonEmpty(os.Getenv("STRIPE_ENTERPRISE_PRICE_ID"), os.Getenv("JOLTRIN_STRIPE_ENTERPRISE_PRICE_ID")) - simulateStr := strings.ToLower(os.Getenv("STRIPE_SIMULATE")) - simulate := simulateStr == "true" || simulateStr == "1" || secretKey == "" - - cfg := governance.StripeConfig{ - SecretKey: secretKey, - WebhookSecret: webhookSecret, - PublishableKey: publishableKey, - ProPriceID: proPriceID, - EnterprisePriceID: entPriceID, - SuccessURL: firstNonEmpty(os.Getenv("STRIPE_SUCCESS_URL"), "/app?checkout=success"), - CancelURL: firstNonEmpty(os.Getenv("STRIPE_CANCEL_URL"), "/app?checkout=canceled"), - Simulate: simulate, + cfg := loadStripeConfig(os.Getenv) + if ready := governance.AssessBilling(cfg); ready.Mode == "live" && !ready.Pro.Available { + fmt.Fprintf(os.Stderr, "billing: live Stripe key set but Pro checkout is off, missing: %s\n", strings.Join(ready.Pro.Missing, ", ")) } // Subscriptions, webhook idempotency keys, and enterprise inquiries are @@ -134,6 +170,7 @@ func handleGetPlan(w http.ResponseWriter, r *http.Request) { "stripe_configured": cfg.SecretKey != "" && !cfg.Simulate, "publishable_key": cfg.PublishableKey, "simulate_mode": cfg.Simulate, + "checkout": governance.AssessBilling(cfg), }) } @@ -171,6 +208,14 @@ func handleCreateCheckoutSession(w http.ResponseWriter, r *http.Request) { } sess, err := getBillingService().CreateCheckoutSession(r.Context(), tenantID, req.Email, targetTier) + if errors.Is(err, governance.ErrEnterpriseContactSales) { + writeJSONError(w, http.StatusConflict, "Enterprise is contact-sales only. Use the enterprise contact form.") + return + } + if errors.Is(err, governance.ErrBillingNotConfigured) { + writeJSONError(w, http.StatusServiceUnavailable, "checkout is not available yet: billing is not fully configured") + return + } if err != nil { writeJSONError(w, http.StatusInternalServerError, "failed to create checkout session: "+err.Error()) return @@ -244,9 +289,21 @@ func handleSimulateCheckout(w http.ResponseWriter, r *http.Request) { tier = governance.TierPro } + // Only meaningful in simulation mode. With live Stripe keys this route + // would otherwise be an unauthenticated way to grant a paid tier. + cfg := getBillingService().Config() + if !cfg.Simulate { + http.NotFound(w, r) + return + } + // Deliver simulated webhook internally to trigger authoritative state update payload := governance.ConstructSimulatedWebhookPayload("checkout.session.completed", sessionID, tenantID, tier) - _, err := getBillingService().HandleWebhook(r.Context(), payload, "") + sig := "" + if cfg.WebhookSecret != "" { + sig = governance.GenerateStripeSignatureHeader(payload, cfg.WebhookSecret, time.Now()) + } + _, err := getBillingService().HandleWebhook(r.Context(), payload, sig) if err != nil && !strings.Contains(err.Error(), "duplicate") { writeJSONError(w, http.StatusInternalServerError, "failed to simulate checkout activation: "+err.Error()) return @@ -298,6 +355,14 @@ func handleBillingWebhook(w http.ResponseWriter, r *http.Request) { return } + // This endpoint is public. With no signing secret there is no way to + // tell a real Stripe event from a forged one, so refuse instead of + // accepting unsigned events. + if getBillingService().Config().WebhookSecret == "" { + writeJSONError(w, http.StatusServiceUnavailable, "webhook signing secret is not configured") + return + } + // Limit body size to 1MB payload, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 1<<20)) if err != nil { diff --git a/tools/httpserver/billing_handler_test.go b/tools/httpserver/billing_handler_test.go index c8ea6c7bc..58a18f584 100644 --- a/tools/httpserver/billing_handler_test.go +++ b/tools/httpserver/billing_handler_test.go @@ -360,3 +360,131 @@ func TestHandleBillingWebhook_DuplicateIgnoredGracefully(t *testing.T) { t.Errorf("expected status 'ignored_duplicate', got %v", resp["status"]) } } + +func envFrom(m map[string]string) func(string) string { + return func(k string) string { return m[k] } +} + +func TestLoadStripeConfig_NoKeysMeansSimulation(t *testing.T) { + cfg := loadStripeConfig(envFrom(nil)) + if !cfg.Simulate || cfg.SecretKey != "" { + t.Fatalf("expected simulation with no keys, got %+v", cfg) + } + if r := governance.AssessBilling(cfg); r.Mode != "simulated" || r.Enterprise.Mode != "contact_sales" { + t.Fatalf("unexpected readiness %+v", r) + } +} + +func TestLoadStripeConfig_LiveKeyWithoutPriceOrURLsIsNotReady(t *testing.T) { + cfg := loadStripeConfig(envFrom(map[string]string{"STRIPE_SECRET_KEY": "sk_test_placeholder"})) + r := governance.AssessBilling(cfg) + if r.Mode != "live" || r.Pro.Available { + t.Fatalf("live key alone must not enable checkout: %+v", r) + } +} + +func TestLoadStripeConfig_PublicURLBuildsAbsoluteReturnURLs(t *testing.T) { + cfg := loadStripeConfig(envFrom(map[string]string{ + "STRIPE_SECRET_KEY": "sk_test_placeholder", + "STRIPE_WEBHOOK_SECRET": "whsec_placeholder", + "STRIPE_PRO_PRICE_ID": "price_pro_real", + "JOLTRIN_PUBLIC_URL": "https://app.example.test/", + })) + if cfg.SuccessURL != "https://app.example.test/app?checkout=success&session_id={CHECKOUT_SESSION_ID}" { + t.Errorf("unexpected success URL %q", cfg.SuccessURL) + } + if r := governance.AssessBilling(cfg); !r.Pro.Available || r.Enterprise.Mode != "contact_sales" { + t.Fatalf("expected Pro ready and Enterprise contact-sales, got %+v", r) + } +} + +func withBillingService(t *testing.T, cfg governance.StripeConfig) { + t.Helper() + old := billingService + billingService = governance.NewDefaultBillingService(cfg, getServerFeatureGate()) + t.Cleanup(func() { billingService = old }) +} + +func TestHandleGetPlan_ReportsCheckoutReadiness(t *testing.T) { + withBillingService(t, governance.StripeConfig{SecretKey: "sk_test_placeholder"}) + + w := httptest.NewRecorder() + handleGetPlan(w, httptest.NewRequest(http.MethodGet, "/api/billing/plan", nil)) + + var resp struct { + Checkout governance.BillingReadiness `json:"checkout"` + } + if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil { + t.Fatal(err) + } + if resp.Checkout.Mode != "live" || resp.Checkout.Pro.Available || len(resp.Checkout.Pro.Missing) == 0 { + t.Fatalf("expected live but not ready, got %+v", resp.Checkout) + } + if bytes.Contains(w.Body.Bytes(), []byte("sk_test_placeholder")) { + t.Fatal("plan response leaked the secret key") + } +} + +func TestHandleCreateCheckoutSession_EnterpriseIsContactSales(t *testing.T) { + withBillingService(t, governance.StripeConfig{Simulate: true}) + + body, _ := json.Marshal(map[string]any{"tier": "enterprise", "email": "a@example.com"}) + w := httptest.NewRecorder() + handleCreateCheckoutSession(w, httptest.NewRequest(http.MethodPost, "/api/billing/checkout", bytes.NewReader(body))) + if w.Code != http.StatusConflict { + t.Fatalf("expected 409, got %d: %s", w.Code, w.Body.String()) + } +} + +func TestHandleCreateCheckoutSession_LiveNotConfiguredIs503(t *testing.T) { + withBillingService(t, governance.StripeConfig{SecretKey: "sk_test_placeholder"}) + + body, _ := json.Marshal(map[string]any{"tier": "pro", "email": "a@example.com"}) + w := httptest.NewRecorder() + handleCreateCheckoutSession(w, httptest.NewRequest(http.MethodPost, "/api/billing/checkout", bytes.NewReader(body))) + if w.Code != http.StatusServiceUnavailable { + t.Fatalf("expected 503, got %d: %s", w.Code, w.Body.String()) + } +} + +func TestHandleSimulateCheckout_NotFoundInLiveMode(t *testing.T) { + gate := getServerFeatureGate() + gate.SetTier(governance.TierCore) + withBillingService(t, governance.StripeConfig{SecretKey: "sk_test_placeholder", WebhookSecret: "whsec_placeholder"}) + + w := httptest.NewRecorder() + handleSimulateCheckout(w, httptest.NewRequest(http.MethodGet, "/api/billing/checkout/simulate?tier=pro", nil)) + if w.Code != http.StatusNotFound { + t.Fatalf("expected 404, got %d", w.Code) + } + if gate.Tier() != governance.TierCore { + t.Fatalf("simulate route must not change the tier in live mode, got %s", gate.Tier()) + } +} + +func TestHandleBillingWebhook_RefusedWithoutSigningSecret(t *testing.T) { + gate := getServerFeatureGate() + gate.SetTier(governance.TierCore) + withBillingService(t, governance.StripeConfig{SecretKey: "sk_test_placeholder"}) + + payload := governance.ConstructSimulatedWebhookPayload("checkout.session.completed", "evt_no_secret_handler", "tenant-x", governance.TierPro) + w := httptest.NewRecorder() + handleBillingWebhook(w, httptest.NewRequest(http.MethodPost, "/api/billing/webhook", bytes.NewReader(payload))) + if w.Code != http.StatusServiceUnavailable { + t.Fatalf("expected 503, got %d", w.Code) + } + if gate.Tier() != governance.TierCore { + t.Fatalf("unsigned event must not change the tier, got %s", gate.Tier()) + } +} + +func TestLoadStripeConfig_UnsetPlaceholderStaysInSimulation(t *testing.T) { + cfg := loadStripeConfig(envFrom(map[string]string{ + "STRIPE_SECRET_KEY": "unset", + "STRIPE_WEBHOOK_SECRET": "unset", + "STRIPE_PUBLISHABLE_KEY": "unset", + })) + if !cfg.Simulate || cfg.SecretKey != "" || cfg.WebhookSecret != "" || cfg.PublishableKey != "" { + t.Fatalf("the Key Vault placeholder must be treated as empty, got %+v", cfg) + } +} From 587b5ac6b23e38356f347e1ac0022cd2783626b8 Mon Sep 17 00:00:00 2001 From: Gerard Louis Andres Recinto Date: Fri, 2 Oct 2026 09:33:18 -0700 Subject: [PATCH 4/4] Potential fix for pull request finding 'CodeQL / Missing regular expression anchor' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- tests/homepage.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/homepage.spec.ts b/tests/homepage.spec.ts index 93fcb0211..05378bff4 100644 --- a/tests/homepage.spec.ts +++ b/tests/homepage.spec.ts @@ -60,7 +60,7 @@ test.describe('Homepage', () => { const html = await (await request.get(path)).text(); expect(html, path).toContain(`