feat(vex): Postgres persistence for Excititor + VexLens + VexHub hardening

Excititor: new migration 003_vex_claim_store.sql and PostgresVexClaimStore
replace the in-memory claim tracking. ExcititorPersistenceExtensions wires
the store; ExcititorMigrationTests updated. Archives S001 demo seed.

VexLens: new migration 002_noise_gating_state.sql with
PostgresGatingStatisticsStore, PostgresSnapshotStore, and
PostgresNoiseGatingJson bring noise-gating state onto disk. New
VexLensRuntimeDatabaseOptions + AuthorityIssuerDirectoryAdapter +
VexHubStatementProvider provide the runtime wiring. WebService tests cover
the persistence, the issuer-directory adapter, and the statement provider.

VexHub: WebService Program, endpoints, middleware, models, and policies
tightened; VexExportCompatibilityTests exercise the Concelier↔VexHub export
contract.

Docs: excititor, vex-hub (architecture + integration guide), and vex-lens
architecture pages updated to match the new persistence and verification
paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-04-15 11:15:31 +03:00
parent ee93c0bac2
commit 291c3d3ad4
47 changed files with 3932 additions and 213 deletions

View File

@@ -158,6 +158,7 @@ Schema: `vex`
- PRIMARY KEY (`digest`, `name`)
- **Observations/linksets** - use the append-only Postgres linkset schema already defined for `IAppendOnlyLinksetStore` (tables `vex_linksets`, `vex_linkset_observations`, `vex_linkset_disagreements`, `vex_linkset_mutations`) with indexes on `(tenant, vulnerability_id, product_key)` and `updated_at`.
- **Claims** - `vex.claims` stores normalized, queryable claim projections keyed by deterministic `claim_hash`, with JSONB columns for product/document metadata plus indexes on `(tenant, provider_id, vulnerability_id, product_key, last_seen)` and `(tenant, vulnerability_id, last_seen)`.
- **Graph overlays** - materialized cache table `vex_overlays` (tenant, purl, advisory_id, source) storing JSONB payloads that follow `docs/modules/excititor/schemas/vex_overlay.schema.json` (schemaVersion 1.0.0). Cache eviction via `cached_at + ttl_seconds`; overlays regenerate when linkset or observation hashes change.
**Canonicalisation & hashing**
@@ -175,11 +176,11 @@ List/query `/vex/raw` via `SELECT ... FROM vex.vex_raw_documents WHERE tenant=@t
- `IVexRawStore` Postgres implementation enforces append-only inserts; duplicate `digest` => no-op; duplicate (`tenant`, `provider_id`, `source_uri`, `etag`) with new digest inserts a new row and sets `supersedes_digest`.
- `IVexRawWriteGuard` runs before insert; tenant is mandatory on every query and write.
**Rollout**
**Runtime convergence**
1. Add migration under `src/Excititor/__Libraries/StellaOps.Excititor.Storage.Postgres/Migrations` creating the tables/indexes above.
2. Implement `PostgresVexRawStore` and switch WebService/Worker DI to `AddExcititorPostgresStorage`.
3. Update `/vex/raw` endpoints/tests to the PostgreSQL store.
1. `StellaOps.Excititor.WebService` and `StellaOps.Excititor.Worker` resolve `IVexProviderStore`, `IVexConnectorStateRepository`, and `IVexClaimStore` from `AddExcititorPersistence`; the live hosts do not register in-memory fallbacks.
2. `StellaOps.Excititor.Persistence` owns startup migrations for the `vex` schema, including `vex.claims` creation and cleanup of historical demo rows from older local installs.
3. The Excititor migration assembly embeds only active top-level SQL files. Archived pre-1.0 scripts and demo-seed SQL are excluded so startup/test migration loaders do not replay historical or fake runtime state.
---