sparda-mcp 0.71.5 → 0.72.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # SPARDA
2
2
 
3
- <div align="center">`r`n <img src="https://raw.githubusercontent.com/zakariagharzouli/sparda/main/assets/sparda-readme-banner-dark-1600x480.png" alt="SPARDA — AI writes. SPARDA proves." width="800" />`r`n</div>
3
+ <div align="center">
4
+ <img src="assets/sparda-readme-banner-dark-1600x480.png" alt="SPARDA — AI writes. SPARDA proves." width="800" />
5
+ </div>
4
6
 
5
7
  <br/>
6
8
 
@@ -156,14 +158,11 @@ npx sparda-mcp apocalypse
156
158
  ```
157
159
 
158
160
  This command reads the compiled `.sparda/ubg.json` (with zero source code parsing at runtime) and discharges five static correctness obligations:
159
-
160
- - **Unguarded Mutation (Critical)**: Flags any mutation path that does not cross a security `guard`.
161
- - **Non-Atomic Aggregate Write (High)**: Flags when an API writes to multiple tables of the same Consistency Domain (Aggregate) outside a single transaction scope.
162
- - **Unvalidated Constrained Write (Medium)**: Flags writes into columns with declared invariants (CHECK, NOT NULL, UNIQUE parsed from your `.sql` DDL **or `schema.prisma`**, Prisma enums included) without prior validation (Zod/Pydantic).
163
- - **Irreversible Observable Effect (High)**: Flags out-of-process actions (like Stripe charges) that happen alongside state writes without a structural compensation path (like a catch-refund).
164
- - **Taint Flow Analysis (High)**: Tracks untrusted input variables through the AST to ensure they do not corrupt critical sinks.
165
- - **Guard Dominance (Medium)**: Proves that top-level security guards cannot be bypassed by nested or overlapping sibling routes.
166
- - **Aggregate Member Bypass (Info)**: Flags mutating a member table directly without routing through the aggregate root.
161
+ * **Unguarded Mutation (Critical)**: Flags any mutation path that does not cross a security `guard`.
162
+ * **Non-Atomic Aggregate Write (High)**: Flags when an API writes to multiple tables of the same Consistency Domain (Aggregate) outside a single transaction scope.
163
+ * **Unvalidated Constrained Write (Medium)**: Flags writes into columns with declared invariants (CHECK, NOT NULL, UNIQUE parsed from your `.sql` DDL **or `schema.prisma`**, Prisma enums included) without prior validation (Zod/Pydantic).
164
+ * **Irreversible Observable Effect (High)**: Flags out-of-process actions (like Stripe charges) that happen alongside state writes without a structural compensation path (like a catch-refund).
165
+ * **Aggregate Member Bypass (Info)**: Flags mutating a member table directly without routing through the aggregate root.
167
166
 
168
167
  To save your current graph as a safe baseline:
169
168
 
@@ -172,10 +171,9 @@ npx sparda-mcp apocalypse --save-baseline
172
171
  ```
173
172
 
174
173
  Subsequent runs will diff the candidate graph against this baseline to detect regression vectors:
175
-
176
- - Deletion of any security `guard` (Critical).
177
- - Deletion of a database SQL invariant (High).
178
- - API blast radius expansion (Medium).
174
+ * Deletion of any security `guard` (Critical).
175
+ * Deletion of a database SQL invariant (High).
176
+ * API blast radius expansion (Medium).
179
177
 
180
178
  If any Critical or High finding is found, `apocalypse` exits with a non-zero code to block your CI pipeline.
181
179
 
@@ -201,10 +199,9 @@ Recording is two lines in your app (ESM), with deterministic sampling and GDPR r
201
199
 
202
200
  ```js
203
201
  import { getFlightBox } from 'sparda-mcp/src/flight/box.js';
204
- const box = getFlightBox();
205
- box.arm();
206
- app.use(box.middleware({ sample: 100 })); // 1 request in 100; passwords/tokens redacted by default
207
- const db = box.wrapClient(pgPool); // your query client, tapped
202
+ const box = getFlightBox(); box.arm();
203
+ app.use(box.middleware({ sample: 100 })); // 1 request in 100; passwords/tokens redacted by default
204
+ const db = box.wrapClient(pgPool); // your query client, tapped
208
205
  ```
209
206
 
210
207
  The closed loop nobody else has: **production bug → recorded flight → failing test → AI writes the fix → `apocalypse` proves the fix breaks no guard, invariant or transaction → deploy.** Replay is per-request (concurrent-race capture is out of scope for v1 — stated, not hidden).
@@ -221,7 +218,7 @@ npx sparda-mcp heal <flightId> --check --expect '{"status":404}'
221
218
 
222
219
  The brief is built from the graph itself — it hands the fixer the handler's `file:line`, the capabilities the fix must not grow, and the guards it must not remove. Then the **gate** — the actual product — proves the fix on three axes at once:
223
220
 
224
- 1. **Behavior** — lenient replay of the recorded flight (same deterministic inputs) now produces the _expected_ response, not the recorded bug. The fix may reformulate a query (the tap is relabeled, allowed); it may **not** change the effect order or kinds.
221
+ 1. **Behavior** — lenient replay of the recorded flight (same deterministic inputs) now produces the *expected* response, not the recorded bug. The fix may reformulate a query (the tap is relabeled, allowed); it may **not** change the effect order or kinds.
225
222
  2. **Compiler laws** — `verify` still passes: the graph is still sound and deterministic.
226
223
  3. **No regression** — `apocalypse` diff against the frozen pre-fix graph: zero new critical/high findings, no guard removed, no blast radius grown.
227
224
 
@@ -229,11 +226,11 @@ The brief is built from the graph itself — it hands the fixer the handler's `f
229
226
  ✓ HEALED & PROVEN — same recorded inputs, correct output, zero law broken, zero protection lost. Ship it.
230
227
  ```
231
228
 
232
- The gate is honest in both directions: an unfixed bug, or a "fix" that silently drops a guard, keeps it **closed** (exit 1). This is the difference between an AI that writes plausible code and a system that _proves_ the code is correct — the trust layer the agent era is missing.
229
+ The gate is honest in both directions: an unfixed bug, or a "fix" that silently drops a guard, keeps it **closed** (exit 1). This is the difference between an AI that writes plausible code and a system that *proves* the code is correct — the trust layer the agent era is missing.
233
230
 
234
231
  ## Any Backend On Earth: OpenAPI Lowering
235
232
 
236
- SPARDA parses Express, FastAPI, Flask and Next.js natively — and **every other stack through the format the industry already agreed on**. Go, Java, Rails, Laravel, .NET: if it has an OpenAPI spec, it compiles.
233
+ SPARDA parses Express, FastAPI and Next.js natively — and **every other stack through the format the industry already agreed on**. Go, Java, Rails, Laravel, .NET: if it has an OpenAPI spec, it compiles.
237
234
 
238
235
  ```bash
239
236
  npx sparda-mcp ubg --openapi openapi.json
@@ -261,6 +258,11 @@ To undo everything: **`npx sparda-mcp remove`** restores your code byte-for-byte
261
258
 
262
259
  ## The promise — every word is backed by a test in CI
263
260
 
261
+ <div align="center">
262
+ <img src="assets/features-presentation.png" alt="SPARDA Features" width="800" />
263
+ </div>
264
+
265
+ <br/>
264
266
 
265
267
  1. **Three minutes, one command.** AST scan, router generation, reversible injection — no config.
266
268
  2. **Try it for free, leave for free.** `npx sparda-mcp remove` restores your code **byte-for-byte** (tested on JS, TS, Python, even Windows CRLF files). No trace, no lock-in.
@@ -269,7 +271,7 @@ To undo everything: **`npx sparda-mcp remove`** restores your code byte-for-byte
269
271
  5. **Nothing leaves your machine.** No telemetry to us, no cloud, local key auth, 4 exact-pinned dependencies.
270
272
  6. **What it learns is never lost.** Diagnoses, descriptions, settings — versioned with your git, surviving every re-init.
271
273
 
272
- What we _don't_ promise: the honest limits in [docs/SECURITY.md](./docs/SECURITY.md).
274
+ What we *don't* promise: the honest limits in [docs/SECURITY.md](./docs/SECURITY.md).
273
275
 
274
276
  ## How it works
275
277
 
@@ -286,52 +288,34 @@ What we _don't_ promise: the honest limits in [docs/SECURITY.md](./docs/SECURITY
286
288
  ## What SPARDA gives your AI
287
289
 
288
290
  ### Operate, not just read
289
-
290
291
  Every route becomes a tool that runs against your live process — real auth, real data,
291
292
  warm connections. One call to **`sparda_get_context`** hands the AI the whole living
292
293
  picture: enabled tools, suggested workflows, runtime telemetry, quarantine state, and
293
294
  immune memory — so every session resumes where the last one stopped.
294
295
 
295
- ### Prove the edit before you commit — the one check an LLM can't do to itself
296
-
297
- The AI just edited a route. Did it quietly drop a guard? It calls **`sparda_prove`** and
298
- finds out **now**, not in a CI run later. The tool recompiles the app to its behavior graph,
299
- discharges the same static obligations as `sparda apocalypse`, and returns a deterministic
300
- verdict — the exact word the CLI and badge emit, so it can never over-claim (a low-coverage
301
- clean app reads `SURFACE`, never a bare `PROVEN`). Save a baseline once
302
- (`sparda apocalypse --save-baseline`) and every later `sparda_prove` flags any finding with
303
- `regression: true` — the guard your edit removed, the route it dropped, the blast radius it
304
- grew. That's _"AI writes. SPARDA proves."_ inside the edit loop. Clients that list MCP prompts
305
- also get the **`prove-my-edit`** workflow.
306
-
307
296
  ### Write-safety: the AI can't write until you say so
308
-
309
297
  - Writes (POST/PUT/DELETE) ship **disabled**. Enable them per tool in `sparda.json`; your choice survives every re-init.
310
298
  - An enabled write is **never executed on the first call**. SPARDA returns an `awaiting_confirmation` envelope — a single-use token plus a preview of the action — and commits only after an explicit confirm step.
311
299
  - When your client supports MCP elicitation, that confirmation prompt appears **in the AI's own UI**.
312
300
  - **Proof-after-write**: every successful write is followed by a read-back of the same resource, so the AI — and you — see the real effect, not a hopeful guess.
313
301
 
314
302
  ### Your app defends itself — zero LLM on the hot path
315
-
316
303
  - **Quarantine.** A tool that returns 3 consecutive 5xx is quarantined: further calls get a `503` with a reason and a retry delay instead of hammering your broken route. After a cooldown it half-opens for a single probe.
317
304
  - **Latency & anomaly flags.** The router learns each route's baseline and flags deviations locally, in a few lines of math.
318
305
  - **Adaptive diagnosis, only on surprise.** A genuinely new failure wakes your AI client's own model to diagnose it once; the diagnosis is cached as an "antibody" in `sparda.json`, so the same failure later costs zero tokens. Cloning your code doesn't clone its immune memory.
319
306
 
320
307
  ### A free intelligence layer, zero API key
321
-
322
308
  On first connection your AI client's own model (via MCP sampling) rewrites raw routes
323
309
  into business-language tool descriptions and proposes multi-step workflows — cached in
324
310
  `sparda.json` and exposed as MCP prompts. Nothing to configure, nothing to pay.
325
311
 
326
312
  ### It gets cheaper the more you use it
327
-
328
313
  - **Response recycling.** When a read keeps returning the same answer, SPARDA serves the next identical call straight from memory — without touching your host app. Reads only; writes always hit the host.
329
314
  - **A recycling gauge.** `GET /mcp/stats` counts how many calls were answered from SPARDA's own knowledge vs. how many paid the host route. It reads 0% on day one and fills with usage — a measure, never a promise.
330
315
 
331
316
  ### Tools nobody wrote — Labs, opt-in, default OFF
332
-
333
317
  Turn it on with `"labs": { "recordSequences": true }` in `sparda.json`. SPARDA then
334
- notices when one tool's output feeds the next tool's input and records the _circuit_
318
+ notices when one tool's output feeds the next tool's input and records the *circuit*
335
319
  structure only (tool names, argument names, counts), never your data. A read-only
336
320
  circuit seen enough times **crystallizes into a composite tool**, announced
337
321
  mid-session: one call runs the whole chain, auto-feeding each step from the previous
@@ -339,13 +323,11 @@ step's real response. Write routes are never absorbed — their per-call confirm
339
323
  always stands.
340
324
 
341
325
  ### Living context & telemetry
342
-
343
326
  `GET /mcp/stats` (per-tool calls/errors, tool "purity", quarantine state) and
344
327
  `GET /mcp/events` (errors, latency anomalies, cached diagnoses) expose exactly what
345
328
  your app is doing — surfaced to the AI as live notifications.
346
329
 
347
330
  ## Built for AI clients: the bundled Skill
348
-
349
331
  SPARDA ships with an Agent Skill ([`SKILL.md`](./SKILL.md)) that teaches any compatible
350
332
  AI client how to drive a SPARDA server to its **full potential** — call
351
333
  `sparda_get_context` first, exploit response recycling, honor quarantine, prefer
@@ -356,20 +338,13 @@ runtime, so the guidance never goes stale.
356
338
  ## Supported frameworks
357
339
 
358
340
  - **Next.js App Router (13/14/15)** — file-based injection. SPARDA creates a catch-all route handler. It natively resolves wrapped handlers (`export const POST = withAuth(h)`) and deep effect chains.
359
- - **NestJS** — AST-based router injection. Deeply resolves Multi-hop Dependency Injection (Controller → Service → Repository), inherited DI, and `baseUrl`/`paths` imports. Fully supports composite decorators (`applyDecorators`). Resolves ORM writes: Prisma, Kysely, and TypeORM injected repositories (`@InjectRepository(Entity)` → `this.repo.save()`).
360
- - **Strapi** — Native AST ingestion of Strapi content-types, core controllers, and custom routes.
361
- - **Express 4/5** (JS/TS, ESM/CJS) — AST-based router injection. Deeply resolves external controllers, Mongoose schemas, barrel re-exports, and inline handlers. Uses dynamic tree-scanning to find non-standard entry points (`bootstrap.ts`, etc).
341
+ - **NestJS** — AST-based router injection. Deeply resolves Multi-hop Dependency Injection (Controller → Service → Repository), inherited DI, and `baseUrl`/`paths` imports. Supports Prisma, TypeORM, and Kysely.
342
+ - **Express 4/5** (JS/TS, ESM/CJS) — AST-based router injection. Deeply resolves external controllers, Mongoose schemas, and barrel re-exports. Uses dynamic tree-scanning to find non-standard entry points (`bootstrap.ts`, etc).
362
343
  - **MedusaJS** — Native AST ingestion of complex e-commerce routing.
363
344
  - **Any Backend On Earth (Go, Java, Rails, Laravel)** — Compiles flawlessly from OpenAPI 3.x specs.
364
345
  - **FastAPI** (Python >= 3.9) — AST-based router injection.
365
346
 
366
- ### Effects it resolves (what makes the irreversibility & atomicity proofs bite)
367
-
368
- - **Databases** — Prisma (incl. named/multiline relations and interactive `$transaction(tx ⇒ …)`), TypeORM, Kysely, Drizzle, Knex, Sequelize, Mongoose, and raw SQL. Foreign keys become aggregate/consistency domains, so a multi-table write outside a transaction is caught.
369
- - **External side-effects** — recognized by call shape and by import origin, so an irreversible outbound effect next to a DB write is proven compensable-or-not: `fetch`/axios/got, Stripe, Twilio, SendGrid/Resend/nodemailer, AWS SDK v3 (`send(new PutObjectCommand())`), and other payment/mail/cloud/queue clients. A read on such a client stays a non-observable GET — no false alarms.
370
-
371
347
  ## Security posture (honest)
372
-
373
348
  - 4 runtime dependencies, exact-pinned.
374
349
  - **Dynamic Local Key Resolution.** The generated router contains no baked secrets. It resolves authorization keys at runtime from the `SPARDA_LOCAL_KEY` environment variable or the local gitignored `.sparda/key` file, and fails closed (503) when neither is found. For custom production or staging setups, you can override this behavior by exposing `SPARDA_LOCAL_KEY` in your environment.
375
350
  - Local key on every router call; self-reference loop protection; 30s timeouts; 8 KB output truncation.
@@ -379,24 +354,26 @@ runtime, so the guidance never goes stale.
379
354
  Full threat model and known gaps: [docs/SECURITY.md](./docs/SECURITY.md).
380
355
 
381
356
  ## Documentation
382
-
383
357
  - [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) — how `init`, the injected router, and the bridge fit together, plus the `sparda.json` schema.
384
358
  - [docs/SECURITY.md](./docs/SECURITY.md) — threat model, defenses, and honest known gaps.
385
359
  - [docs/TESTING.md](./docs/TESTING.md) — how the promises above are kept honest in CI.
386
360
  - [docs/ERRORS.md](./docs/ERRORS.md) — the error knowledge base.
387
361
 
388
362
  ## Beyond the open core
389
-
390
363
  SPARDA is free, including in production (see License). Team-scale capabilities —
391
364
  fine-grained per-person access policies and a signed, tamper-evident audit log — are
392
365
  planned for a future paid tier. The open core stands on its own; nothing here is
393
366
  crippled to upsell you.
394
367
 
395
368
  ## License
396
-
397
369
  [Business Source License 1.1](./LICENSE) — free to use, including in production.
398
370
  You may not resell SPARDA or offer it as a competing commercial service.
399
371
  Each version converts to Apache 2.0 four years after its release.
400
372
 
373
+ <div align="center">
374
+ <img src="assets/github-star.png" alt="Leave a Star" width="600" />
375
+ </div>
376
+
377
+ <br/>
401
378
 
402
379
  By [Residual Labs](https://residual-labs.fr)
package/SKILL.md CHANGED
@@ -13,11 +13,11 @@ description: >-
13
13
 
14
14
  A SPARDA server is driven by a compiled **Unified Behavior Graph (UBG)** — the graph SPARDA's compiler produces from the host application's states, transitions, permissions, and side-effects, serialized under the **SBIR** specification. Instead of exposing raw, disconnected endpoints, SPARDA compiles the app into a deterministic behavioral model. The local **SPARDA Runtime** dynamically executes this graph inside the live host process, powering the MCP interface, the Twin simulation clone, and the Immune system offline.
15
15
 
16
- > This skill covers the **runtime** (driving a live MCP server) — the live half of SPARDA's trust layer: _"AI writes. SPARDA proves."_ The same graph also powers dev-time proof commands you run in the app's repo — `sparda review` (the behavior diff of a PR), `apocalypse` (prove the deploy), `timeless` (record/replay a request), `heal` (prove a fix), `mirror` (serve the graph), `ubg` (compile), `verify` (prove the compiler's laws). Those are CLI, not MCP tools; see the project README.
16
+ > This skill covers the **runtime** (driving a live MCP server) — the live half of SPARDA's trust layer: *"AI writes. SPARDA proves."* The same graph also powers dev-time proof commands you run in the app's repo — `sparda review` (the behavior diff of a PR), `apocalypse` (prove the deploy), `timeless` (record/replay a request), `heal` (prove a fix), `mirror` (serve the graph), `ubg` (compile), `verify` (prove the compiler's laws). Those are CLI, not MCP tools; see the project README.
17
17
 
18
18
  ## Rule 0 — call `sparda_get_context` first, every session
19
19
 
20
- Before anything else, call **`sparda_get_context`** (no params). It returns the _live_ state of the SPARDA Behavior Graph:
20
+ Before anything else, call **`sparda_get_context`** (no params). It returns the *live* state of the SPARDA Behavior Graph:
21
21
 
22
22
  - the active routes/tools, workflows, and type-propagated schemas;
23
23
  - `runtime` — current stats (calls, errors, quarantine states, Twin mode active);
@@ -35,45 +35,19 @@ Read it to orient yourself inside the graph. `sparda_info` gives a lighter summa
35
35
  parameter schema was only partially inferred — pass arguments carefully.
36
36
  - **Meta-tools** — `sparda_get_context`, `sparda_info`,
37
37
  `sparda_list_disabled_tools`, `sparda_confirm`.
38
- - **The proof tool** — `sparda_prove`. Call it **after you edit a route, before you
39
- commit** — see _Prove your own edit_ below. It's the one check you can't do to
40
- yourself by re-reading your code.
41
38
  - **Composite tools** — labelled `[Labs circuit ×N]`, `readOnly`. One call runs a
42
- whole proven multi-step chain (see _Crystallized circuits_ below).
39
+ whole proven multi-step chain (see *Crystallized circuits* below).
43
40
 
44
41
  Only **enabled** tools appear. Write tools are hidden until the user opts in, so a
45
- missing write is a config state, not an error — see _Writing safely_.
46
-
47
- ## Prove your own edit — call `sparda_prove` before you commit
48
-
49
- This is the tool an LLM needs most and can least fake. After you edit a route,
50
- **call `sparda_prove`** — it recompiles the app to its behavior graph and discharges
51
- the same static obligations as `sparda apocalypse` (unguarded mutation, non-atomic
52
- aggregate write, unvalidated constrained write), then returns a deterministic verdict.
53
-
54
- - **Focus it.** Pass `route` with the method+path you just touched (e.g.
55
- `{ "route": "DELETE /orders" }`) to narrow the finding list. The **verdict still
56
- reflects the whole app** — a filter never buys you a greener light.
57
- - **Read the verdict honestly.** `PROVEN` / `PARTIAL` are safe to commit. `SURFACE`
58
- and `NO_PROOF` mean SPARDA _couldn't resolve enough to prove it_ — that is
59
- "unknown", **never** a pass. The word is the exact one the CLI and badge emit; it
60
- physically cannot over-claim.
61
- - **The regression check is the point.** If a baseline was saved
62
- (`sparda apocalypse --save-baseline` on a known-good state), any finding with
63
- `regression: true` means _your edit_ removed a guard, dropped a route, or grew the
64
- blast radius vs the last proven state. Fix those before committing — this is the
65
- check you cannot perform by re-reading your own diff.
66
- - Clients that list MCP prompts also see **`prove-my-edit`**, the built-in workflow
67
- that walks these steps.
42
+ missing write is a config state, not an error — see *Writing safely*.
68
43
 
69
44
  ## Exploit the intelligence layer (this is the "full potential")
70
45
 
71
46
  **1. Response-recycling flywheel — make repeated reads free.**
72
- When the _same_ read tool returns a byte-identical result for the _same_ arguments
47
+ When the *same* read tool returns a byte-identical result for the *same* arguments
73
48
  **3 times within 30 seconds**, SPARDA serves the next identical call straight from
74
49
  RAM (`servedByFlywheel: true`) **without touching the host app**. So:
75
-
76
- - Don't fear repeating stable GETs — repetition is what _activates_ the cache.
50
+ - Don't fear repeating stable GETs — repetition is what *activates* the cache.
77
51
  - Don't bolt your own client-side cache on top; you'd hide the signal that lets
78
52
  SPARDA recycle, and you'd lose freshness control.
79
53
  - Watch `recycling.flywheel.servedFromMemory` climb in context — that's free work.
@@ -81,7 +55,7 @@ RAM (`servedByFlywheel: true`) **without touching the host app**. So:
81
55
 
82
56
  **2. Circuit-breaker / quarantine — stop hammering a sick backend.**
83
57
  After **3 consecutive 5xx** on a tool, SPARDA quarantines it: subsequent calls
84
- return **HTTP 503** with `reason` and `retryInMs` _instead of_ hitting the failing
58
+ return **HTTP 503** with `reason` and `retryInMs` *instead of* hitting the failing
85
59
  host. Honor `retryInMs` — do not retry-loop. Check `runtime.quarantine` in context
86
60
  before depending on a tool. After a cooldown (~60s) the tool half-opens for one
87
61
  probe; one more 5xx re-quarantines it.
@@ -94,7 +68,7 @@ single **composite tool** for that chain and announces it mid-session via
94
68
  call and it's marked read-only. (Writes are never absorbed into a circuit.)
95
69
 
96
70
  **4. Adaptive immunity — read the diagnosis before retrying.**
97
- Repeated, unfamiliar failures trigger a _one-shot_ LLM diagnosis that SPARDA caches
71
+ Repeated, unfamiliar failures trigger a *one-shot* LLM diagnosis that SPARDA caches
98
72
  as an "antibody" (keyed by `source|tool|status`). Recurrences reuse the cached
99
73
  diagnosis at zero cost. When an error event carries a diagnosis, **read it** and
100
74
  adapt — don't blindly retry the same call.
@@ -104,13 +78,11 @@ an `immune` event in `/mcp/events`. Treat it as a hint to back off or warn the u
104
78
 
105
79
  **6. Twin Simulation Mode — practice safely on a clone.**
106
80
  When `/mcp/stats` or `sparda_get_context.runtime` contains `"twin": true`, you are connected to a safe, in-memory mock clone of the application.
107
-
108
81
  - All GET reads return learned exemplars (observed response shapes and mock values).
109
82
  - All write tools return simulated `202` echoes but do not write to database or external APIs.
110
83
  - Use this twin mode to practice multi-step workflows, debug tool sequences, and test your plans without touching the live production backend.
111
84
 
112
85
  **7. Grammar & Evolution — discover optimal workflows.**
113
-
114
86
  - You can query or contribute to the app's grammar (`.sparda/grammar.json`). The grammar maps valid sequences of tool calls (edges).
115
87
  - Running `sparda evolve` mutates and runs candidate chains against the twin. The successful evolved sequences are suggested as mid-session workflows.
116
88
 
@@ -167,7 +139,7 @@ Writes are **disabled by default**. The protocol is not optional:
167
139
  manifest validity, the semantic/immune cache, host reachability, and quarantine;
168
140
  it exits non-zero so it can gate CI.
169
141
  - **Formal Deployment Proof** → `sparda apocalypse` reads the compiled graph (`ubg.json`) and proves five correctness obligations: catches unguarded mutations, non-atomic aggregate writes, unvalidated writes to constrained tables, uncompensated observable effects, and aggregate root bypasses. Run `sparda apocalypse --save-baseline` to store the reference graph; subsequent runs diff against the baseline to catch dropped guards, dropped SQL invariants, or grown blast radiuses.
170
- - **Safety Matrix Report** → `sparda dossier` generates an ultra-premium, self-contained HTML matrix of the app's safety proof, ideal for security engineers and audit compliance (Bloc C / Shadow tier).
142
+ - **Safety Matrix Report** → `sparda dossier` generates an ultra-premium, self-contained HTML matrix of the app's safety proof, ideal for security engineers and audit compliance.
171
143
  - **Deep Framework Resolution** → SPARDA natively traces multi-hop Dependency Injection in NestJS, external controllers in Express, and wrapped handlers in Next.js, mapping them into the final Behavior Graph.
172
144
  - **OpenAPI Ingestion** → Run `sparda ubg --openapi <openapi_spec.json>` to compile any non-JS/Python backend (Go, Java, Rails, Laravel, .NET) into a Unified Behavior Graph by mapping security schemes into guards and request/response structures. (JSON specs only — convert YAML once with `npx -y js-yaml spec.yaml > spec.json`.)
173
145
  - **Executing the Graph (No code mock)** → Run `sparda mirror` to host a mock HTTP simulation server directly from `ubg.json` without any backend code. Enforces authentication guards, returns typed responses, and acts as a contract sandbox.
@@ -179,8 +151,7 @@ Writes are **disabled by default**. The protocol is not optional:
179
151
  - **Learn exemplars** → Start your live app and run `sparda twin --learn` to fetch actual response data and construct `.sparda/twin.json` locally.
180
152
 
181
153
  ---
182
-
183
- _This skill ships with `sparda-mcp` and is regenerated from SPARDA's capability
154
+ *This skill ships with `sparda-mcp` and is regenerated from SPARDA's capability
184
155
  surface each release, so it tracks new tools and behaviors. The **live, per-project**
185
156
  tool list, stats, and workflows always come from `sparda_get_context` at runtime —
186
- trust it over any static list._
157
+ trust it over any static list.*
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "sparda-mcp",
3
- "version": "0.71.5",
4
- "mcpName": "io.github.zakariagharzouli/sparda-mcp",
5
- "description": "AI writes. SPARDA proves. A deterministic, offline gate that catches when an AI edit removes a guard, exposes a route, or breaks an invariant \u2014 no API key, right in the agent edit loop.",
3
+ "version": "0.72.1",
4
+ "mcpName": "io.github.zyx77550/sparda-mcp",
5
+ "description": "AI writes. SPARDA proves. A deterministic, offline gate that catches when an AI edit removes a guard, exposes a route, or breaks an invariant no API key, right in the agent edit loop.",
6
6
  "type": "module",
7
7
  "repository": {
8
8
  "type": "git",
@@ -28,6 +28,8 @@
28
28
  "format": "prettier --write \"**/*.{js,cjs,mjs}\"",
29
29
  "format:check": "prettier --check \"**/*.{js,cjs,mjs}\"",
30
30
  "bench:check": "node bench/check-readme.mjs",
31
+ "bench:pde": "node bench/pde-ternary.mjs",
32
+ "bench:soundness": "node bench/soundness/run.mjs",
31
33
  "mutation": "node tests/mutation/run.mjs",
32
34
  "wedge": "node bench/wedge.mjs",
33
35
  "release:check": "node scripts/release-gate.mjs",
@@ -19,7 +19,7 @@ import {
19
19
  buildProofObjects,
20
20
  } from '../ubg/apocalypse.js';
21
21
  import { surveyBlindspots, coveragePct } from '../ubg/blindspots.js';
22
- import { premiseFor, withPremiseGaps, basisFrom } from '../ubg/premise.js';
22
+ import { certifiableOrgan, withPremiseGaps, basisFrom } from '../ubg/premise.js';
23
23
  import { atomicWriteFileSync as atomicWrite } from '../server/persistence.js';
24
24
 
25
25
  // version travels with the proof so an audit knows which prover produced it
@@ -74,7 +74,7 @@ export async function runApocalypse(opts) {
74
74
  // decides whether a tree ships — so it is the last place that may certify an app whose
75
75
  // route table nobody checked. `premiseFor` keeps the opt-in boundary: the runtime
76
76
  // oracle needs `--probe`, the boot-free convention oracle always runs.
77
- const premise = await premiseFor(canonical, report, {
77
+ const premise = await certifiableOrgan('apocalypse').premise(canonical, report, {
78
78
  cwd: opts.cwd,
79
79
  probe: opts.probe,
80
80
  });
@@ -10,7 +10,7 @@ import { compileUBG } from '../ubg/compile.js';
10
10
  import { canonicalizeGraph } from '../ubg/schema.js';
11
11
  import { checkGraph, verdictOf, badgeFor } from '../ubg/apocalypse.js';
12
12
  import { surveyBlindspots, coveragePct } from '../ubg/blindspots.js';
13
- import { premiseFor, withPremiseGaps, basisFrom } from '../ubg/premise.js';
13
+ import { certifiableOrgan, withPremiseGaps, basisFrom } from '../ubg/premise.js';
14
14
 
15
15
  export async function runBadge(opts) {
16
16
  const { graph, report } = compileUBG(opts.cwd, { write: false });
@@ -19,7 +19,7 @@ export async function runBadge(opts) {
19
19
  // A badge is the artifact that leaves the repo. It may not read green over an app
20
20
  // whose route table was never checked — that is the one place a false claim travels
21
21
  // furthest and is hardest to retract.
22
- const premise = await premiseFor(canonical, report, {
22
+ const premise = await certifiableOrgan('badge').premise(canonical, report, {
23
23
  cwd: opts.cwd,
24
24
  probe: opts.probe,
25
25
  });
@@ -10,7 +10,7 @@ import path from 'node:path';
10
10
  import { compileUBG } from '../ubg/compile.js';
11
11
  import { canonicalizeGraph } from '../ubg/schema.js';
12
12
  import { checkGraph, verdictOf, verdictState } from '../ubg/apocalypse.js';
13
- import { premiseFor, withPremiseGaps, basisFrom } from '../ubg/premise.js';
13
+ import { certifiableOrgan, withPremiseGaps, basisFrom } from '../ubg/premise.js';
14
14
  import { surveyBlindspots, coveragePct } from '../ubg/blindspots.js';
15
15
  import { buildCapsule } from '../ubg/immunity.js';
16
16
  import { AXES, POLARITY_SYMBOL, exposedAxes } from '../ubg/polarity.js';
@@ -22,7 +22,7 @@ export async function runDossier(opts) {
22
22
  const { findings, polarity } = checkGraph(canonical);
23
23
  // the public report — same rule as the badge: it must not describe an app SPARDA
24
24
  // never fully had
25
- const premise = await premiseFor(canonical, compiled.report, {
25
+ const premise = await certifiableOrgan('dossier').premise(canonical, compiled.report, {
26
26
  cwd: opts.cwd,
27
27
  probe: opts.probe,
28
28
  });