up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-03 00:10:19 +02:00
parent ea1d58a89b
commit 37cba83708
158 changed files with 147438 additions and 867 deletions

View File

@@ -0,0 +1,39 @@
# Graph Analytics Gaps (GA1GA10) Remediation Plan
**Sprint:** 0207-0001-0001 (Experience & SDKs 180.C)
**Artifacts produced:** schemas + samples for analytics results/bundles; governance rules; test/fixture expectations.
## Objectives (mapped to GA1GA10)
- **GA1 — Versioned analytics schemas:** `analytics-result.schema.json` defines versioned result payloads with `schemaVersion` + `algorithmVersion`.
- **GA2 — Deterministic seeds/rerun-hash CI:** every job records `seed`, `rerunHash = sha256(inputs+seed+algorithmVersion)`, and must replay to identical outputs.
- **GA3 — Privacy/tenant redaction:** results require `tenant` field; redaction rules apply before export (`redactions[]` logged).
- **GA4 — Baseline datasets/fixtures:** ship minimal deterministic fixture set under `src/Graph/__Tests/Fixtures/analytics-baseline/` (TODO when code added) and sample bundle here.
- **GA5 — Performance budgets/quotas:** default budgets captured in schema (`budgetSeconds`, `maxNodes`, `maxEdges`); jobs failing budgets emit `status=budget_exceeded`.
- **GA6 — Explainability metadata:** include `inputs`, `seed`, `algorithmVersion`, `parameters`, `provenance` (source hashes) for replay.
- **GA7 — Checksums + DSSE for exports:** bundle schema carries per-file SHA-256 plus optional DSSE signature envelope reference.
- **GA8 — Algorithm versioning:** `algorithmVersion` semver and `changeLogUrl` required; breaking changes bump MAJOR.
- **GA9 — Offline analytics bundle schema:** `analytics-bundle.schema.json` documents offline package with manifest, dataset hashes, redactions, and optional signatures.
- **GA10 — SemVer/change-log governance:** bundles must cite `changeLogUrl`; release notes must link to signed manifests; exports failing SemVer gating are rejected.
## Schemas & Samples
- `docs/modules/graph/analytics/analytics-result.schema.json`
- `docs/modules/graph/analytics/analytics-bundle.schema.json`
- Sample bundle: `docs/modules/graph/analytics/samples/analytics-bundle.sample.json`
## Rules of Engagement
1. **Determinism:** fixed `seed`; stable ordering of nodes/edges; `rerunHash` must match across runs given same inputs/seed.
2. **Redaction before export:** `redactions[]` enumerates removed fields per tenant policy; exports lacking redaction entries are invalid for multi-tenant bundles.
3. **Signatures (optional but encouraged):** DSSE/JWS envelopes over `bundle.manifest` and `resultHash` using offline keys; record under `signatures[]`.
4. **Offline readiness:** no network fetch during analysis or validation; datasets referenced by hash + relative path.
5. **Performance budgets:** defaults—`budgetSeconds: 30`, `maxNodes: 50000`, `maxEdges: 200000`; overridable per job but must be logged.
## Implementation Hooks
- API/Indexer must emit analytics results conforming to `analytics-result.schema.json`.
- Export jobs must validate bundles against `analytics-bundle.schema.json` and attach DSSE refs when available.
- CI: add rerun-hash check in analytics test pipeline using fixture bundle; fail on drift.
## Open Follow-ups
- Add real fixtures under `src/Graph/__Tests/Fixtures/analytics-baseline/` mirrored in Offline Kit.
- Wire DSSE signing in release pipeline once signing keys for Graph are provisioned.
## Evidence
- Schemas + sample committed in this sprint. Link in sprint Decisions & Risks. Tests to follow in analytics pipeline PR.***

View File

@@ -0,0 +1,115 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stellaops.local/graph/analytics-bundle.schema.json",
"title": "Graph Analytics Bundle (Offline)",
"type": "object",
"additionalProperties": false,
"required": [
"bundleId",
"tenant",
"schemaVersion",
"analyticsResults",
"datasets",
"manifest",
"hashes",
"createdAt"
],
"properties": {
"bundleId": { "type": "string", "pattern": "^analytics-bundle:[A-Za-z0-9._:-]+$" },
"tenant": { "type": "string", "minLength": 1 },
"schemaVersion": { "type": "string", "pattern": "^1\\.\\d+\\.\\d+$" },
"createdAt": { "type": "string", "format": "date-time" },
"analyticsResults": {
"type": "array",
"items": {
"type": "object",
"required": ["analysisId", "resultPath", "resultHash", "algorithmVersion", "schemaVersion"],
"additionalProperties": false,
"properties": {
"analysisId": { "type": "string" },
"resultPath": { "type": "string" },
"resultHash": { "type": "string", "pattern": "^sha256:[A-Fa-f0-9]{64}$" },
"schemaVersion": { "type": "string" },
"algorithmVersion": { "type": "string" },
"rerunHash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
}
},
"uniqueItems": true
},
"datasets": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "path", "hash"],
"additionalProperties": false,
"properties": {
"id": { "type": "string" },
"path": { "type": "string" },
"hash": { "type": "string", "pattern": "^sha256:[A-Fa-f0-9]{64}$" },
"redactions": { "type": "array", "items": { "type": "string" }, "uniqueItems": true }
}
},
"uniqueItems": true
},
"manifest": {
"type": "array",
"items": {
"type": "object",
"required": ["path", "sha256", "size"],
"additionalProperties": false,
"properties": {
"path": { "type": "string" },
"sha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" },
"size": { "type": "integer", "minimum": 0 },
"contentType": { "type": "string" }
}
},
"uniqueItems": true
},
"hashes": {
"type": "object",
"additionalProperties": false,
"properties": {
"bundleSha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" },
"manifestSha256": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$" }
}
},
"signatures": {
"type": "array",
"items": {
"type": "object",
"required": ["type", "keyId", "signature"],
"additionalProperties": false,
"properties": {
"type": { "type": "string", "enum": ["dsse", "jws-detached"] },
"keyId": { "type": "string" },
"signature": { "type": "string" },
"envelopeDigest": { "type": "string", "pattern": "^sha256:[A-Fa-f0-9]{64}$" }
}
}
},
"metadata": {
"type": "object",
"additionalProperties": false,
"properties": {
"budgets": {
"type": "object",
"additionalProperties": false,
"properties": {
"budgetSeconds": { "type": "number", "minimum": 0, "default": 30 },
"maxNodes": { "type": "integer", "minimum": 0, "default": 50000 },
"maxEdges": { "type": "integer", "minimum": 0, "default": 200000 }
}
},
"offline": {
"type": "object",
"additionalProperties": false,
"properties": {
"sealed": { "type": "boolean", "default": true },
"provenance": { "type": "string" }
}
}
}
}
}
}

View File

@@ -0,0 +1,80 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stellaops.local/graph/analytics-result.schema.json",
"title": "Graph Analytics Result",
"type": "object",
"additionalProperties": false,
"required": [
"schemaVersion",
"algorithmVersion",
"analysisId",
"tenant",
"inputs",
"seed",
"rerunHash",
"metrics",
"result",
"createdAt"
],
"properties": {
"schemaVersion": { "type": "string", "pattern": "^1\\.\\d+\\.\\d+$" },
"algorithmVersion": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" },
"changeLogUrl": { "type": "string", "format": "uri" },
"analysisId": { "type": "string", "minLength": 1 },
"tenant": { "type": "string", "minLength": 1 },
"inputs": {
"type": "object",
"additionalProperties": false,
"properties": {
"snapshotIds": { "type": "array", "items": { "type": "string" }, "uniqueItems": true },
"filters": { "type": "object" },
"datasetHash": { "type": "string", "pattern": "^sha256:[A-Fa-f0-9]{64}$" }
}
},
"seed": { "type": "integer", "minimum": 0 },
"parameters": { "type": "object" },
"rerunHash": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
"metrics": {
"type": "object",
"additionalProperties": false,
"properties": {
"durationSeconds": { "type": "number", "minimum": 0 },
"budgetSeconds": { "type": "number", "minimum": 0 },
"maxNodes": { "type": "integer", "minimum": 0 },
"maxEdges": { "type": "integer", "minimum": 0 },
"nodesProcessed": { "type": "integer", "minimum": 0 },
"edgesProcessed": { "type": "integer", "minimum": 0 },
"status": { "type": "string", "enum": ["ok", "budget_exceeded", "failed"] }
},
"required": ["durationSeconds", "budgetSeconds", "status"]
},
"result": {
"type": "object",
"description": "Algorithm-specific payload (centrality, community detection, reachability, etc.).",
"additionalProperties": true
},
"provenance": {
"type": "object",
"additionalProperties": false,
"properties": {
"inputsHash": { "type": "string", "pattern": "^sha256:[A-Fa-f0-9]{64}$" },
"resultHash": { "type": "string", "pattern": "^sha256:[A-Fa-f0-9]{64}$" },
"manifestHash": { "type": "string", "pattern": "^sha256:[A-Fa-f0-9]{64}$" }
}
},
"redactions": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"field": { "type": "string" },
"reason": { "type": "string" },
"policy": { "type": "string" }
},
"required": ["field", "reason"]
}
},
"createdAt": { "type": "string", "format": "date-time" }
}
}

View File

@@ -0,0 +1,62 @@
{
"$schema": "../analytics-bundle.schema.json",
"bundleId": "analytics-bundle:graph:2025-12-02T00-00Z",
"tenant": "default",
"schemaVersion": "1.0.0",
"createdAt": "2025-12-02T00:00:00Z",
"analyticsResults": [
{
"analysisId": "centrality-2025-12-02",
"resultPath": "results/centrality.ndjson",
"resultHash": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd",
"schemaVersion": "1.0.0",
"algorithmVersion": "2.1.0",
"rerunHash": "29d58b9fdc5c4e65b26c03f3bd9f442ff0c7f8514b8a9225f8b6417ffabc0101"
}
],
"datasets": [
{
"id": "snapshot-2025-12-01",
"path": "datasets/graph-snapshot-2025-12-01.tzst",
"hash": "sha256:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"redactions": ["user.email", "org.internalNotes"]
}
],
"manifest": [
{
"path": "results/centrality.ndjson",
"sha256": "89abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567",
"size": 104857,
"contentType": "application/x-ndjson"
},
{
"path": "datasets/graph-snapshot-2025-12-01.tzst",
"sha256": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"size": 2097152,
"contentType": "application/octet-stream"
}
],
"hashes": {
"bundleSha256": "0f0e0d0c0b0a09080706050403020100ffeeddccbbaa99887766554433221100",
"manifestSha256": "aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55aa55"
},
"signatures": [
{
"type": "dsse",
"keyId": "graph-analytics-dev-pub",
"signature": "MEQCIDevGraphSig==",
"envelopeDigest": "sha256:bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66bb66"
}
],
"metadata": {
"budgets": {
"budgetSeconds": 30,
"maxNodes": 50000,
"maxEdges": 200000
},
"offline": {
"sealed": true,
"provenance": "offline-kit:graph-analytics:2025-12"
}
}
}