Skip to content
Product · Architecture

The machine that produced sample-1.

This page has no marketing. Every service, schema, language, and technology below is traceable to a file in the repository. If the code changes, this page changes. If a claim here isn't in the code, remove it.

Seven stages · one direction

Source in. Signed ontology out.

Every artifact under /evidence/* is produced by exactly this pipeline. Each stage is a real service in services/. Stages communicate via NATS JetStream events (with idempotency guaranteed by per-service processed_events tables) and share PostgreSQL as the per-service system of record.

Softinel pipeline: source-intake → parser → knowledge-graph → dependency → digital-twin → verification → policy01source-intakeGo02parserRust03knowledge-graphRust04dependencyGo05digital-twinRust06verificationGo07policyGosnapshot.uploadedsnapshot.parsedsnapshot.graph_builtsnapshot.deps_loadedsnapshot.twin_readysnapshot.verifiedIN · uploaded snapshot (zip → MinIO)OUT · signed evidence pack (Ed25519 JWS)
  1. 01

    source-intake

    Go
    readsClient POST /v1/snapshots (multipart zip)
    writesMinIO/S3 object · NATS event snapshot.uploaded

    Boundary. Validates the archive, computes its content hash, persists to object storage, emits an event.

  2. 02

    parser

    Rust · Tree-sitter · Tokio
    readsNATS snapshot.uploaded → downloads zip from MinIO
    writesparsed_snapshots (Postgres) · IR JSON-Lines (MinIO) · NATS snapshot.parsed

    For each file, detects the language and runs the matching Tree-sitter grammar (tree-sitter-javascript, tree-sitter-typescript, tree-sitter-python, tree-sitter-rust, tree-sitter-go). Extracts a normalized IR —FileIR{ symbols[], imports[], calls[] } — writes it as JSONL to MinIO. No language-specific AST details leak past this stage.

  3. 03

    knowledge-graph

    Rust · Postgres · Neo4j
    readsNATS snapshot.parsed → reads IR JSONL from MinIO
    writesgraph_snapshots (Postgres) · file/symbol/import/call nodes and edges (Neo4j) · NATS snapshot.graph_built

    Populates the canonical ontology. Files, symbols, imports, and call edges become graph nodes and relationships in Neo4j via the neo4rs driver. The snapshot summary row (graph_snapshots) records loading counters and status.

  4. 04

    dependency

    Go · Postgres
    readsNATS snapshot.parsed
    writesdependencies (Postgres, one row per dep) · NATS snapshot.deps_loaded

    Extracts direct dependencies per ecosystem (npm, pypi, go, cargo, maven) from the manifest files. Deduped by (snapshot_id, ecosystem, name, manifest_path).

  5. 05

    digital-twin

    Rust · Postgres · Neo4j
    readsNATS snapshot.graph_built
    writescomponent_health per file · component_health_summary per snapshot

    Computes per-file metrics (LoC, symbols, fan-out, fan-in, imports) and the per-snapshot rollup (avg/max/p95 fan-out). This is the versioned, living layer of the ontology.

  6. 06

    verification

    Go · Postgres
    readsNATS snapshot.graph_built + snapshot.deps_loaded
    writesfindings (Postgres) · verification_runs · NATS snapshot.verified

    Every finding is a query against the ontology + supporting evidence. Rows include rule_id, agent, severity, confidence, evidence (JSONB), and verification_level ∈ [0,5]. A unique index on (snapshot_id, rule_id, file_path, start_line) enforces deduplication.

  7. 07

    policy

    Go · Postgres
    readsNATS snapshot.verified
    writesverdicts (Postgres, exactly one per snapshot)

    Evaluates the org's policy document (JSONB) against the findings. Emits exactly one row per snapshot with verdict { pass, warn, block }, plus gate_results (per-condition JSONB breakdown) and by_severity rollup. This is what verdict.json in sample-1 is derived from.

The signing step

After the seven stages produce the pack, an Ed25519 JWS is written over the SHA-256 of every component file. The public key is published at /.well-known/jwks.json (kid = softinel-evidence-2026-07). The signing code is 40 lines of Go in tools/build-evidence/main.go — no external crypto dependency beyond the Go standard library.

The ontology, verbatim from migrations

These are the tables. This is the shape.

The ontology isn't abstract — it is a concrete set of PostgreSQL tables (plus mirrored Neo4j nodes/edges for graph queries). Below is the columns-that-matter view of each table, copied from the SQL under services/*/migrations/0001_init.up.sql.

parser

parsed_snapshots

services/parser/migrations/0001_init.up.sql
  • snapshot_idUUID · unique per uploaded archive
  • ir_storage_keyMinIO key holding the IR JSONL blob
  • files_parsedINT · files successfully parsed
  • total_symbolsINT · symbols extracted across all files
  • total_importsINT
  • total_callsINT · intra-module call edges
  • language_statsJSONB · counts per language
  • statusparsed | partial | failed
knowledge-graph

graph_snapshots

services/knowledge-graph/migrations/0001_init.up.sql
  • snapshot_idUUID · one-to-one with parsed_snapshots
  • files_loadedINT
  • symbols_loadedINT
  • imports_loadedINT
  • calls_loadedINT
  • external_modulesINT · imports pointing outside the workspace
  • statusbuilt | partial | failed

Individual nodes and edges live in Neo4j via the neo4rs driver — this table is the snapshot ledger.

dependency

dependencies

services/dependency/migrations/0001_init.up.sql
  • ecosystemnpm | pypi | go | cargo | maven
  • nameTEXT
  • versionTEXT · exact resolved version
  • version_rangeTEXT · manifest declaration
  • manifest_pathTEXT · where the declaration lives
  • is_devBOOL
  • is_optionalBOOL

Unique on (snapshot_id, ecosystem, name, manifest_path).

digital-twin

component_health

services/digital-twin/migrations/0001_init.up.sql
  • file_pathTEXT
  • languageTEXT
  • locINT
  • symbolsINT
  • fan_outINT · outgoing CALLS
  • fan_inINT · incoming CALLS
  • importsINT

Plus component_health_summary rollups: total_files, total_symbols, avg / max / p95 fan-out.

verification

findings

services/verification/migrations/0001_init.up.sql
  • rule_idTEXT · e.g. SEC-EVAL-001
  • agentsecurity | architecture | quality | performance | dependency
  • severitycritical | high | medium | low | info
  • confidenceDOUBLE PRECISION ∈ [0,1]
  • file_path/start_line/end_linelocation — nullable for project-wide findings
  • evidenceJSONB · sources, extracts, reasoning
  • verification_levelINT ∈ [0,5] · how deeply this was checked
  • statusopen | acknowledged | resolved | dismissed | false_positive

Unique on (snapshot_id, rule_id, file_path, start_line) — same rule at same location doesn't double-count.

policy

verdicts

services/policy/migrations/0001_init.up.sql
  • snapshot_idUUID · exactly one verdict per snapshot
  • verdictpass | warn | block
  • gate_resultsJSONB · per-condition satisfied/violated + detail
  • total_findingsINT
  • by_severityJSONB · rollup by severity

One row per snapshot — the UNIQUE constraint on snapshot_id enforces that.

Language coverage — Phase 1

Five languages today, via one grammar substrate.

The parser detects languages by extension and dispatches to the matching Tree-sitter grammar — the same substrate GitHub uses for code search. See services/parser/src/parser/languages.rs for the exact dispatch. Adding a language is a one-line change plus the grammar crate in Cargo.toml.

TypeScript
.ts, .tsx
JavaScript
.js, .jsx, .mjs, .cjs
Python
.py, .pyi
Rust
.rs
Go
.go

Skip patterns (also in languages.rs) exclude node_modules, vendor, dist, build, target, .git, __pycache__, .venv, venv — so the ontology models what you wrote, not what package managers downloaded.

Technology choices, and the reason for each

Boring, defensible, replaceable.

Rust

parser · knowledge-graph · digital-twin

Parsing millions of files is CPU-bound and memory-sensitive. Rust gives us zero-cost abstractions, no GC pauses, and a first-class Tree-sitter ecosystem. Async runtime: Tokio; web layer: Axum; SQL: sqlx (compile-time query verification).

Go

identity · gateway · verification · policy · dependency · orchestrator · reporting · billing · audit · tenant · projects · source-intake · remediation

The API-surface services. Chi router, pgx driver. Cheap deployment (single static binary), predictable memory, fast enough for every non-parser workload.

Python

agents

Language of the LLM/ML ecosystem. The agents service hosts language-model-driven checks — but never inside the decision path. Its outputs land in the same findings table with a lower verification_level until a higher-level pass promotes them.

PostgreSQL

every service · one database per service

Every ontology fact is a Postgres row somewhere. We reach for JSONB where the shape is heterogeneous (evidence, gate_results, policy document), and hard columns everywhere else. No shared schema across services — the process boundary is also the data boundary.

Neo4j

knowledge-graph · digital-twin

Graph queries (reachability, transitive impact, cycle detection) are where relational query planners give up. Neo4j via neo4rs handles those. Postgres remains the ledger; Neo4j is the query surface.

NATS JetStream

every service · durable event stream

Stage-to-stage handoff. Each service subscribes to the events it cares about, records the event id in its processed_events table on first success, and skips on retry. Exactly-once semantics without a distributed transaction.

MinIO (S3-compatible)

source-intake · parser

Snapshot archives and IR JSONL blobs — anything too big or too transient for a database. rust-s3 on the Rust side, AWS SDK on the Go side.

Ed25519 JWS

reporting · tools/build-evidence

The signature over every evidence artifact. Small keys, small signatures, RFC 7515 compact serialisation. Public key published as JWK Set at /.well-known/jwks.json. See the acid-test proof at /evidence/sample-1.

Trust model

Everything is signed. Nothing is post-editable.

The signature over an evidence artifact is Ed25519 over header.payload in JWS compact form. The payload commits to the SHA-256 of every component file. That means:

  • If the findings file changes by a single byte, the manifest's claimed hash no longer matches, and verification fails at that component.
  • If the JWS payload is re-forged with new hashes, the Ed25519 signature no longer verifies against the published key.
  • If the published key is replaced, the kid in the JWS header no longer matches — verifiers refuse the signature explicitly rather than silently accepting the wrong key.
  • Anyone can re-run the generator (tools/build-evidence) locally, compare byte-for-byte, and hold us accountable for drift.
Explicit limits — what today, what next

The honest state of the ontology.

Selling the vision is easy; being honest about the frontier is what earns trust. Today the ontology covers what's listed under Built. The rest is scheduled and traceable in rodemap.txt — but not yet in the model.

Built today
  • Files, symbols, imports, and intra-module call edges across 5 languages.
  • Direct dependencies from package.json, requirements.txt, go.mod, Cargo.toml, pom.xml.
  • Per-file health metrics (LoC, fan-out, fan-in).
  • Verification pipeline with structural + rule-based findings.
  • Policy engine with configurable gates → verdict per snapshot.
  • Signed evidence pack (Ed25519 JWS) verifiable in a browser or with openssl.
Scheduled — not yet in the model
  • Inter-service call graph (RPC / HTTP boundaries as edges).
  • Data-flow analysis across function boundaries (currently rule-level).
  • Transitive dependency resolution + license graph.
  • Runtime signals (traces, error rates) as ontology facts.
  • Deployment topology as first-class nodes.
  • LLM agents promoting verification_level 0→1 findings to 2+ automatically.

If any item in the "Scheduled" column is on the site as if it were shipped today, treat it as a bug and tell us. Marketing debt is worse than technical debt.

Verify the architecture, not just the pitch

Every claim here can be checked.

The pipeline above produced /evidence/sample-1. That artifact is Ed25519-signed. Every finding on it points to a real file:line in samples/vulnerable-web. Open the artifact, click "Verify signature", and every SHA-256 you see gets re-hashed in your browser and compared to the value committed by the signature.

If you want to reproduce the whole thing from source:

# 1. Clone git clone https://github.com/abokenan444/svp-platform cd svp-platform # 2. Regenerate the sample artifact (Go 1.23+, deterministic given the same key) go run ./tools/build-evidence -repo=. # 3. Compare with what we publish diff apps/web/public/evidence/sample-1/verdict.json <(curl -sS https://softinel.com/evidence/sample-1/verdict.json) # → no output = byte-identical content
Ready when you are

Connect your software. Softinel builds the model.

One canonical, connected model of your software. Every question about security, correctness, architecture, and change becomes a query against it — with evidence attached.