feat: Add Storybook configuration and motion tokens implementation

- Introduced Storybook configuration files (`main.ts`, `preview.ts`, `tsconfig.json`) for Angular components.
- Created motion tokens in `motion-tokens.ts` to define durations, easing functions, and transforms.
- Developed a Storybook story for motion tokens showcasing their usage and reduced motion fallback.
- Added SCSS variables for motion durations, easing, and transforms in `_motion.scss`.
- Implemented accessibility smoke tests using Playwright and Axe for automated accessibility checks.
- Created portable and sealed bundle structures with corresponding JSON files for evidence locker.
- Added shell script for verifying notify kit determinism.
This commit is contained in:
StellaOps Bot
2025-12-04 21:36:06 +02:00
parent 600f3a7a3c
commit f214edff82
68 changed files with 1742 additions and 18 deletions

View File

@@ -29,6 +29,7 @@
| 2 | GRAPH-INDEX-28-008 | DONE (2025-11-22) | PREP-GRAPH-INDEX-28-008-UNBLOCK-AFTER-28-007 | Graph Indexer Guild | Provide incremental update & backfill pipeline with change streams, retry/backoff, idempotent ops, backlog metrics. |
| 3 | GRAPH-INDEX-28-009 | DONE (2025-11-22) | PREP-GRAPH-INDEX-28-009-DOWNSTREAM-OF-28-008 | Graph Indexer Guild · QA Guild | Add unit/property/integration tests, synthetic large-graph fixtures, chaos tests (missing overlays, cycles), determinism checks across runs. |
| 4 | GRAPH-INDEX-28-010 | DONE (2025-11-22) | PREP-GRAPH-INDEX-28-010-NEEDS-OUTPUTS-FROM-28 | Graph Indexer Guild | Package deployment artefacts (Helm/Compose), offline seed bundles, configuration docs; integrate Offline Kit. |
| 5 | CARTO-GRAPH-21-002-INGEST | DONE (2025-12-04) | graph.inspect.v1 contract published | Graph Indexer Guild (`src/Graph/StellaOps.Graph.Indexer`) | Add `graph.inspect.v1` transformer + tests so Graph Indexer can ingest Concelier/Excititor inspector payloads (advisory + VEX linkouts, relationships). |
## Execution Log
| Date (UTC) | Update | Owner |
@@ -43,6 +44,7 @@
| 2025-11-22 | Implemented analytics jobs (28-007), change-stream/backfill pipeline (28-008), determinism fixtures/tests (28-009), and packaging/offline doc updates (28-010); status set to DONE. | Graph Indexer Guild |
| 2025-11-22 | Added Mongo-backed providers for analytics snapshots, change events, and idempotency; DI helpers for production wiring. | Graph Indexer Guild |
| 2025-11-22 | Added Mongo database DI registration helper + integration tests; updated packaging env vars for connection/db names. | Graph Indexer Guild |
| 2025-12-04 | Added `graph.inspect.v1` ingestion support (transformer + unit test) aligned to Cartographer inspector contract; status recorded as CARTO-GRAPH-21-002-INGEST DONE. | Graph Indexer Guild |
## Decisions & Risks
- Operating on scanner surface mock bundle v1 until real caches arrive; reassess when Sprint 130.A delivers caches.

View File

@@ -59,7 +59,7 @@
| Schema readiness | BLOCKED | Waiting on AdvisoryAI + orchestrator envelopes; no DOING until frozen. |
| Crypto routing approval | DONE | Defaults recorded in `docs/security/crypto-registry-decision-2025-11-18.md`; implement in EvidenceLocker/CLI. |
| Template & filename normalization | DONE (2025-11-17) | Renamed to `SPRINT_0161_0001_0001_evidencelocker.md`; structure aligned to sprint template. |
| EB1EB10 policy freeze | OPEN | Gap plan at `docs/modules/evidence-locker/eb-gaps-161-007-plan.md`; DSSE predicate/log policy, redaction map, and chunking rules still need sign-off. |
| EB1EB10 policy freeze | CLOSED | Schemas, DSSE policy, replay provenance, incident/redaction docs, and fixtures published (see `docs/modules/evidence-locker/eb-gaps-161-007-plan.md`); SemVer/changelog still pending under EB10. |
### Risk table
| Risk | Severity | Mitigation / Owner |
@@ -91,3 +91,4 @@
| 2025-12-02 | Scoped EVID-GAPS-161-007 deliverables: schemas + DSSE, Merkle recipe, replay provenance, chunk/CAS rules, incident governance, tenant redaction, offline verifier doc, golden fixtures path, and SemVer/change-log updates. | Project Mgmt |
| 2025-12-04 | Moved EVID-GAPS-161-007 to DOING; drafted EB1/EB2 schemas, offline verifier guide, gap plan, and golden fixtures path. | Project Mgmt |
| 2025-12-04 | Updated attestation, replay, incident-mode docs with DSSE subject=Merkle root, log policy, replay provenance block, and signed incident toggles; added CAS/Merkle rules to bundle packaging. | Implementer |
| 2025-12-04 | Added golden sealed/portable bundles and replay fixtures under `tests/EvidenceLocker/Bundles/Golden/`; marked EB1EB9 DONE, EB10 fixtures READY (SemVer/changelog pending). | Implementer |

View File

@@ -34,11 +34,12 @@
| 11 | NOTIFY-RISK-68-001 | BLOCKED (2025-11-22) | Depends on 67-001. | Notifications Service Guild | Per-profile routing, quiet hours, dedupe for risk alerts; integrate CLI/Console preferences. |
| 12 | NOTIFY-DOC-70-001 | DONE (2025-11-02) | — | Notifications Service Guild | Document split between legacy `src/Notify` libs and new `src/Notifier` runtime; update architecture docs. |
| 13 | NOTIFY-AIRGAP-56-002 | DONE | — | Notifications Service Guild · DevOps Guild | Bootstrap Pack notifier configs with deterministic secrets handling and offline validation. |
| 14 | NOTIFY-GAPS-171-014 | TODO | NR1NR10 defined in `31-Nov-2025 FINDINGS.md` + `docs/notifications/gaps-nr1-nr10.md`; implement schema/catalog + evidence bundle | Notifications Service Guild / src/Notifier/StellaOps.Notifier | Remediate NR1NR10: publish signed schemas + canonical JSON, enforce tenant scoping/approvals, deterministic rendering, quotas/backpressure + DLQ, retry/idempotency policy, webhook/ack security, redaction/PII limits, observability SLO alerts, offline notify-kit with DSSE, and mandatory simulations + evidence for rule/template changes. |
| 14 | NOTIFY-GAPS-171-014 | DOING (2025-12-04) | NR1NR10 defined; schemas/kit/docs scaffolded; fill hashes + signatures next | Notifications Service Guild / src/Notifier/StellaOps.Notifier | Remediate NR1NR10: publish signed schemas + canonical JSON, enforce tenant scoping/approvals, deterministic rendering, quotas/backpressure + DLQ, retry/idempotency policy, webhook/ack security, redaction/PII limits, observability SLO alerts, offline notify-kit with DSSE, and mandatory simulations + evidence for rule/template changes. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-04 | Scaffolded NR1NR10 artefacts (schemas, catalog, DSSE placeholders, quota/retry/security docs, fixtures, offline kit manifest + verify script) and set NOTIFY-GAPS-171-014 to DOING. | Implementer |
| 2025-12-04 | Authored NR1NR10 section and blueprint (`docs/notifications/gaps-nr1-nr10.md`); unblocked NOTIFY-GAPS-171-014 and set status to TODO. | Implementer |
| 2025-11-19 | Fixed PREP-NOTIFY-OBS-51-001 Task ID (removed trailing hyphen) so dependency lookup works. | Project Mgmt |
| 2025-12-01 | Added NOTIFY-GAPS-171-014 (NR1NR10 from `31-Nov-2025 FINDINGS.md`) to track advisory gap remediation; status TODO pending schema/catalog refresh. | Project Mgmt |

View File

@@ -47,7 +47,7 @@
| 17 | UI-POLICY-DET-01 | DONE | UI-SBOM-DET-01 | UI Guild; Policy Guild (src/Web/StellaOps.Web) | Wire policy gate indicators and remediation hints into Release/Policy flows, blocking publishes when determinism checks fail; coordinate with Policy Engine schema updates. |
| 18 | UI-ENTROPY-40-001 | DONE | - | UI Guild (src/Web/StellaOps.Web) | Visualise entropy analysis per image (layer donut, file heatmaps, "Why risky?" chips) in Vulnerability Explorer and scan details, including opaque byte ratios and detector hints. |
| 19 | UI-ENTROPY-40-002 | DONE | UI-ENTROPY-40-001 | UI Guild; Policy Guild (src/Web/StellaOps.Web) | Add policy banners/tooltips explaining entropy penalties (block/warn thresholds, mitigation steps) and link to raw `entropy.report.json` evidence downloads. |
| 20 | UI-MICRO-GAPS-0209-011 | BLOCKED | Canonical 30-Nov-2025 UI Micro-Interactions advisory published; still need motion token catalog plus a11y/Storybook/Playwright harness in `src/Web/StellaOps.Web`. | UI Guild; UX Guild; Accessibility Guild | Close MI1MI10: define motion tokens + reduced-motion rules, perf budgets, offline/latency/error patterns, component mapping, telemetry schema/flags, deterministic seeds/snapshots, micro-copy localisation, and theme/contrast guidance; add Storybook/Playwright checks. |
| 20 | UI-MICRO-GAPS-0209-011 | DOING | Motion token catalog + Storybook/Playwright a11y harness added in `src/Web/StellaOps.Web`; remaining: component mapping, perf budgets, deterministic snapshots, micro-copy localisation. | UI Guild; UX Guild; Accessibility Guild | Close MI1MI10: define motion tokens + reduced-motion rules, perf budgets, offline/latency/error patterns, component mapping, telemetry schema/flags, deterministic seeds/snapshots, micro-copy localisation, and theme/contrast guidance; add Storybook/Playwright checks. |
## Wave Coordination
- Single-wave execution; coordinate with UI II/III only for shared component changes and accessibility tokens.
@@ -76,6 +76,7 @@
| 5 | Receive SDK parity matrix (Wave B, SPRINT_0208_0001_0001_sdk) to unblock Console data providers and scope exports | UI Guild · SDK Generator Guild | 2025-12-16 | BLOCKED (awaiting SDK parity delivery) |
| 6 | Publish canonical UI Micro-Interactions advisory (MI1MI10) with motion tokens, reduced-motion rules, and fixtures referenced by this sprint | Product Mgmt · UX Guild | 2025-12-06 | DONE |
| 7 | Align sprint working directory to `src/Web/StellaOps.Web` and verify workspace present (was `src/UI/StellaOps.UI`) | UI Guild | 2025-12-05 | DONE (2025-12-04) |
| 8 | Refresh package-lock with new Storybook/a11y devDependencies (registry auth required) | UI Guild · DevEx | 2025-12-06 | TODO |
## Decisions & Risks
| Risk | Impact | Mitigation / Next Step |
@@ -85,10 +86,12 @@
| Entropy evidence format changes | Rework for UI-ENTROPY-* views | Lock to `docs/modules/scanner/entropy.md`; add contract test fixtures before UI wiring. |
| Working directory mismatch (UI vs Web) causes contributors to edit wrong path | Duplicate effort or missing workspace for new tasks | Sprint now points to `src/Web/StellaOps.Web`; Action #7 closed; broadcast path in AGENTS/TASKS updates. |
| Micro-interaction implementation inputs incomplete | UI-MICRO-GAPS-0209-011 blocked on motion token catalog + a11y/Storybook/Playwright harness despite advisory availability | Keep Action #6 closed; open follow-on tasks for token catalog + harness once SDK scopes land. |
| NPM registry auth expired for new devDependencies | Storybook/a11y harness cannot be installed; package-lock not updated | Resolve auth and rerun `npm install` (Action #8) to lock dependencies; dev code committed with pinned versions. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-04 | Added motion token catalog (SCSS + TS), Storybook scaffolding with reduced-motion toggle, and Playwright a11y smoke harness. `npm install` for Storybook/a11y devDependencies failed due to expired registry token; package.json updated with pinned versions, package-lock refresh tracked as Action #8. | Implementer |
| 2025-12-04 | Confirmed canonical Angular workspace is `src/Web/StellaOps.Web` (not `src/UI/StellaOps.UI`); updated working directory, blockers, and Action #7 accordingly. Graph blockers now tied to generated `graph:*` SDK scopes. | Project mgmt |
| 2025-12-04 | Published canonical UI Micro-Interactions advisory (`docs/product-advisories/30-Nov-2025 - UI Micro-Interactions for StellaOps.md`). UI-MICRO-GAPS-0209-011 remains BLOCKED pending motion token catalog + a11y/Storybook/Playwright harness in `src/Web/StellaOps.Web`. | Project mgmt |
| 2025-12-04 | Earlier note: UI-MICRO-GAPS-0209-011 was marked BLOCKED when advisory was still pending and `src/UI/StellaOps.UI` was empty; superseded by publication + path correction the same day. | Project mgmt |

View File

@@ -7,16 +7,16 @@ Working directory: `docs/implplan` (sprint coordination) with artefacts in `docs
## Scope Items
| ID | Deliverable | Artifact / Path | Owner(s) | Acceptance / Notes | Status |
| --- | --- | --- | --- | --- | --- |
| EB1 | Publish canonical manifest schema | `docs/modules/evidence-locker/schemas/bundle.manifest.schema.json` | Evidence Locker Guild | JSON Schema matches EvidenceBundleManifest (bundleId, tenantId, kind, metadata, entries) and captures replay/incident/redaction hooks. | Draft (2025-12-04) |
| EB2 | Publish checksums schema | `docs/modules/evidence-locker/schemas/checksums.schema.json` | Evidence Locker Guild | Canonical map for `checksums.txt`; Merkle root + chunking metadata; sorted entry rule recorded. | Draft (2025-12-04) |
| EB3 | Hash/Merkle recipe doc | `docs/modules/evidence-locker/bundle-packaging.md` (new section) | Evidence Locker Guild | Normative steps for Merkle root + DSSE subject; clarifies gzip/tar invariants and CAS compatibility. | TODO |
| EB4 | Mandatory DSSE predicate/log policy | `docs/modules/evidence-locker/attestation-contract.md` | Evidence Locker Guild · Security Guild | Required claims + signing profiles; Rekor/log policy (optional vs required); aligns with crypto registry defaults. | TODO |
| EB5 | Replay provenance block | `docs/modules/evidence-locker/replay-payload-contract.md` + manifest schema | Evidence Locker Guild · Replay Delivery Guild | Replay digest + DSSE envelope recorded; ordering rules match `DETERMINISTIC_REPLAY.md`; portable bundle retains linkage. | TODO |
| EB6 | Chunking/CAS rules | `checksums.schema.json` + `bundle-packaging.md` | Evidence Locker Guild · Storage/DevOps | Defines chunk sizing, CAS digest, and stability guarantees; CI test to catch ordering changes. | TODO |
| EB7 | Incident-mode signed activation/exit | `docs/modules/evidence-locker/incident-mode.md` | Evidence Locker Guild · Security Guild | Manifest/DSSE captures activation + deactivation events with signer identity; API/CLI steps documented. | TODO |
| EB8 | Tenant isolation + redaction manifest | `bundle-packaging.md` + portable bundle guidance | Evidence Locker Guild · Privacy Guild | Portable bundles omit tenant identifiers; redaction map recorded; verifier asserts redacted fields absent. | TODO |
| EB1 | Publish canonical manifest schema | `docs/modules/evidence-locker/schemas/bundle.manifest.schema.json` | Evidence Locker Guild | JSON Schema matches EvidenceBundleManifest (bundleId, tenantId, kind, metadata, entries) and captures replay/incident/redaction hooks. | DONE (2025-12-04) |
| EB2 | Publish checksums schema | `docs/modules/evidence-locker/schemas/checksums.schema.json` | Evidence Locker Guild | Canonical map for `checksums.txt`; Merkle root + chunking metadata; sorted entry rule recorded. | DONE (2025-12-04) |
| EB3 | Hash/Merkle recipe doc | `docs/modules/evidence-locker/bundle-packaging.md` (new section) | Evidence Locker Guild | Normative steps for Merkle root + DSSE subject; clarifies gzip/tar invariants and CAS compatibility. | DONE (2025-12-04) |
| EB4 | Mandatory DSSE predicate/log policy | `docs/modules/evidence-locker/attestation-contract.md` | Evidence Locker Guild · Security Guild | Required claims + signing profiles; Rekor/log policy (optional vs required); aligns with crypto registry defaults. | DONE (2025-12-04) |
| EB5 | Replay provenance block | `docs/modules/evidence-locker/replay-payload-contract.md` + manifest schema | Evidence Locker Guild · Replay Delivery Guild | Replay digest + DSSE envelope recorded; ordering rules match `DETERMINISTIC_REPLAY.md`; portable bundle retains linkage. | DONE (2025-12-04) |
| EB6 | Chunking/CAS rules | `checksums.schema.json` + `bundle-packaging.md` | Evidence Locker Guild · Storage/DevOps | Defines chunk sizing, CAS digest, and stability guarantees; CI test to catch ordering changes. | DONE (2025-12-04) |
| EB7 | Incident-mode signed activation/exit | `docs/modules/evidence-locker/incident-mode.md` | Evidence Locker Guild · Security Guild | Manifest/DSSE captures activation + deactivation events with signer identity; API/CLI steps documented. | DONE (2025-12-04) |
| EB8 | Tenant isolation + redaction manifest | `bundle-packaging.md` + portable bundle guidance | Evidence Locker Guild · Privacy Guild | Portable bundles omit tenant identifiers; redaction map recorded; verifier asserts redacted fields absent. | DONE (2025-12-04) |
| EB9 | Offline verifier script | `docs/modules/evidence-locker/verify-offline.md` | Evidence Locker Guild | POSIX script included; no network dependencies; emits Merkle root used by DSSE subject. | DONE (2025-12-04) |
| EB10 | Golden bundles/replay fixtures + SemVer/changelog | `tests/EvidenceLocker/Bundles/Golden/` + release notes (TBD) | Evidence Locker Guild · CLI Guild | Golden sealed + portable bundles and replay NDJSON with expected roots; changelog bump covering EB1EB9. | TODO |
| EB10 | Golden bundles/replay fixtures + SemVer/changelog | `tests/EvidenceLocker/Bundles/Golden/` + release notes (TBD) | Evidence Locker Guild · CLI Guild | Golden sealed + portable bundles and replay NDJSON with expected roots; changelog bump covering EB1EB9. | Fixtures READY (2025-12-04); SemVer/changelog PENDING |
## Near-Term Actions (to move EB1EB10 to DONE)
- Wire schemas into EvidenceLocker CI (manifest + checksums validation) and surface in API/CLI OpenAPI/Help.

View File

@@ -51,7 +51,8 @@ Frozen contract for Evidence Bundle v1 covering AdvisoryAI/Concelier/Excititor e
## Attestation linkage
- See `attestation-scope-note.md` for required claims.
- Subject digest should reference the tarball sha256; include `bundle_id` and `tenant`.
- DSSE subject uses the Merkle root derived from `checksums.txt` (sha256 of sorted entry hashes). Record the OCI tarball digest as metadata, not the subject.
## Change log
- 2025-12-04: Updated subject to Merkle root and aligned with EB1EB10 docs/fixtures.
- 2025-11-19: v1 frozen (initial publication). Add real sample tarball + hashes once produced.

View File

@@ -0,0 +1,9 @@
{
"tenant_id": "tenant-123",
"delivery_id": "00000000-0000-4000-8000-000000000001",
"channel": "email",
"subject": "User signup",
"body": "User john@example.com joined",
"redacted_body": "User ***@example.com joined",
"pii_hash": "TBD"
}

View File

@@ -0,0 +1 @@
{"template_id":"tmpl-incident-start","locale":"en-US","channel":"email","expected_hash":"TBD","body_sample_path":"tmpl-incident-start.email.en-US.json"}

View File

@@ -0,0 +1,6 @@
{
"subject": "Incident started: ${incident_id}",
"body": "Incident ${incident_id} started at ${started_at}. Severity: ${severity}.",
"merge_fields": ["incident_id", "started_at", "severity"],
"preview_hash": "TBD"
}

View File

@@ -0,0 +1,10 @@
{
"trace_id": "00000000000000000000000000000001",
"tenant_id": "tenant-123",
"rule_id": "RULE-INCIDENT",
"channel_id": "email-default",
"attributes": {
"delivery_id": "00000000-0000-4000-8000-000000000001",
"status": "sent"
}
}

View File

@@ -0,0 +1,27 @@
groups:
- name: notify-slo
rules:
- alert: NotifyDeliverySuccessSLO
expr: sum(rate(notify_delivery_success_total[5m])) / sum(rate(notify_delivery_total[5m])) < 0.98
for: 10m
labels:
severity: page
annotations:
summary: "Notify delivery success below SLO"
description: "Success ratio below 98% over 10m"
- alert: NotifyBacklogDepthHigh
expr: notify_backlog_depth > 5000
for: 5m
labels:
severity: page
annotations:
summary: "Notify backlog too high"
description: "Backlog depth exceeded 5000 messages"
- alert: NotifyDlqGrowth
expr: rate(notify_dlq_depth[10m]) > 50
for: 10m
labels:
severity: ticket
annotations:
summary: "Notify DLQ growth"
description: "Dead letter queue growing faster than threshold"

View File

@@ -0,0 +1,9 @@
{
"title": "Notify SLO",
"panels": [
{ "title": "Delivery success", "target": "sum(rate(notify_delivery_success_total[5m])) / sum(rate(notify_delivery_total[5m]))" },
{ "title": "Backlog depth", "target": "notify_backlog_depth" },
{ "title": "DLQ depth", "target": "notify_dlq_depth" },
{ "title": "Latency p95", "target": "histogram_quantile(0.95, rate(notify_delivery_latency_seconds_bucket[5m]))" }
]
}

View File

@@ -0,0 +1,7 @@
# Quotas, backpressure, and DLQ (NR4)
- Per-tenant quotas: 500 deliveries/minute default; channel overrides: webhook 200/min, email 120/min, chat 240/min.
- Burst budget: 2x quota for 60 seconds, then hard clamp.
- Backpressure: reject enqueue when backlog > quota*10 or DLQ growth > 5%/min.
- DLQ schema: `docs/notifications/schemas/dlq-notify.schema.json`; redrive requires idempotent `delivery_id`/`dedupe_key`.
- Metrics to alert: backlog depth, DLQ depth, redrive success rate, enqueue reject count.

View File

@@ -0,0 +1,7 @@
# Retry and idempotency policy (NR5)
- `delivery_id`: UUIDv7; `dedupe_key`: hash(event_id + rule_id + channel_id).
- Backoff: exponential with jitter; base 2s, factor 2, max 5 attempts, cap 5 minutes between attempts.
- Connectors must be idempotent; retries reuse the same `dedupe_key` and must not duplicate sends.
- Out-of-order acks ignored: only monotonic `attempt` accepted.
- Record retry outcomes in receipts and include attempt count + reason.

View File

@@ -0,0 +1,20 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/notify/schemas/channel.schema.json",
"title": "Notify Channel Configuration",
"type": "object",
"required": ["schema_version", "tenant_id", "channel_id", "kind", "config"],
"properties": {
"schema_version": { "type": "string", "pattern": "^v[0-9]+\\.[0-9]+$" },
"tenant_id": { "type": "string", "minLength": 1 },
"channel_id": { "type": "string", "pattern": "^[A-Z0-9_-]{4,64}$" },
"kind": { "type": "string", "enum": ["email", "slack", "teams", "webhook", "sms"] },
"config": { "type": "object" },
"secrets_ref": { "type": "object", "additionalProperties": { "type": "string" } },
"rate_limit": { "type": "object" },
"enabled": { "type": "boolean", "default": true },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}

View File

@@ -0,0 +1,20 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/notify/schemas/dlq-notify.schema.json",
"title": "Notify Dead Letter Entry",
"type": "object",
"required": ["schema_version", "tenant_id", "delivery_id", "reason", "payload", "first_failed_at"],
"properties": {
"schema_version": { "type": "string", "pattern": "^v[0-9]+\\.[0-9]+$" },
"tenant_id": { "type": "string", "minLength": 1 },
"delivery_id": { "type": "string", "pattern": "^[0-9a-fA-F-]{18,36}$" },
"reason": { "type": "string" },
"payload": { "type": "object" },
"backoff_attempts": { "type": "integer", "minimum": 0 },
"dedupe_key": { "type": "string" },
"first_failed_at": { "type": "string", "format": "date-time" },
"last_failed_at": { "type": "string", "format": "date-time" },
"redrive_after": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}

View File

@@ -0,0 +1,26 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/notify/schemas/event-envelope.schema.json",
"title": "Notify Event Envelope",
"type": "object",
"required": [
"schema_version",
"tenant_id",
"event_id",
"occurred_at",
"kind",
"payload"
],
"properties": {
"schema_version": { "type": "string", "pattern": "^v[0-9]+\\.[0-9]+$" },
"tenant_id": { "type": "string", "minLength": 1 },
"event_id": { "type": "string", "pattern": "^[0-9a-fA-F-]{18,36}$" },
"occurred_at": { "type": "string", "format": "date-time" },
"kind": { "type": "string", "minLength": 1 },
"correlation_id": { "type": "string" },
"source": { "type": "string" },
"payload": { "type": "object" },
"attributes": { "type": "object", "additionalProperties": { "type": ["string", "number", "boolean", "null"] } }
},
"additionalProperties": false
}

View File

@@ -0,0 +1,14 @@
{
"catalog": "notify-schemas-catalog.json",
"hash_algorithm": "blake3-256",
"canonicalization": "json-normalized-utf8",
"entries": [
{ "file": "event-envelope.schema.json", "digest": "TBD" },
{ "file": "rule.schema.json", "digest": "TBD" },
{ "file": "template.schema.json", "digest": "TBD" },
{ "file": "channel.schema.json", "digest": "TBD" },
{ "file": "receipt.schema.json", "digest": "TBD" },
{ "file": "webhook.schema.json", "digest": "TBD" },
{ "file": "dlq-notify.schema.json", "digest": "TBD" }
]
}

View File

@@ -0,0 +1,6 @@
{
"payloadType": "application/vnd.notify.schema-catalog+json",
"payload": "BASE64_ENCODED_NOTIFY_SCHEMA_CATALOG_TBD",
"signatures": [],
"note": "Placeholder; replace with signed payload once BLAKE3 digest and signing key are available."
}

View File

@@ -0,0 +1,15 @@
{
"catalog_version": "v1.0",
"hash_algorithm": "blake3-256",
"canonicalization": "json-normalized-utf8",
"generated_at": "2025-12-04T00:00:00Z",
"schemas": [
{ "id": "event-envelope", "file": "event-envelope.schema.json", "version": "v1.0", "digest": "TBD" },
{ "id": "rule", "file": "rule.schema.json", "version": "v1.0", "digest": "TBD" },
{ "id": "template", "file": "template.schema.json", "version": "v1.0", "digest": "TBD" },
{ "id": "channel", "file": "channel.schema.json", "version": "v1.0", "digest": "TBD" },
{ "id": "receipt", "file": "receipt.schema.json", "version": "v1.0", "digest": "TBD" },
{ "id": "webhook", "file": "webhook.schema.json", "version": "v1.0", "digest": "TBD" },
{ "id": "dlq", "file": "dlq-notify.schema.json", "version": "v1.0", "digest": "TBD" }
]
}

View File

@@ -0,0 +1,21 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/notify/schemas/receipt.schema.json",
"title": "Notify Delivery Receipt",
"type": "object",
"required": ["schema_version", "tenant_id", "delivery_id", "rule_id", "channel", "status", "sent_at"],
"properties": {
"schema_version": { "type": "string", "pattern": "^v[0-9]+\\.[0-9]+$" },
"tenant_id": { "type": "string", "minLength": 1 },
"delivery_id": { "type": "string", "pattern": "^[0-9a-fA-F-]{18,36}$" },
"rule_id": { "type": "string" },
"channel": { "type": "string" },
"status": { "type": "string", "enum": ["sent", "delivered", "failed", "queued", "acknowledged"] },
"attempt": { "type": "integer", "minimum": 1 },
"sent_at": { "type": "string", "format": "date-time" },
"ack_url": { "type": "string", "format": "uri" },
"response": { "type": "object" },
"errors": { "type": "array", "items": { "type": "string" } }
},
"additionalProperties": false
}

View File

@@ -0,0 +1,37 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/notify/schemas/rule.schema.json",
"title": "Notify Rule",
"type": "object",
"required": [
"schema_version",
"tenant_id",
"rule_id",
"name",
"sources",
"predicates",
"actions",
"approvals_required"
],
"properties": {
"schema_version": { "type": "string", "pattern": "^v[0-9]+\\.[0-9]+$" },
"tenant_id": { "type": "string", "minLength": 1 },
"rule_id": { "type": "string", "pattern": "^[A-Z0-9_-]{4,64}$" },
"name": { "type": "string", "minLength": 1 },
"description": { "type": "string" },
"severity": { "type": "string", "enum": ["info", "low", "medium", "high", "critical"] },
"sources": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
"predicates": { "type": "array", "items": { "type": "object" }, "minItems": 1 },
"actions": {
"type": "array",
"items": { "type": "object" },
"minItems": 1
},
"approvals_required": { "type": "integer", "minimum": 0, "maximum": 3 },
"quiet_hours": { "type": "array", "items": { "type": "string" } },
"simulation_required": { "type": "boolean", "default": true },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}

View File

@@ -0,0 +1,22 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/notify/schemas/template.schema.json",
"title": "Notify Template",
"type": "object",
"required": ["schema_version", "tenant_id", "template_id", "channel", "locale", "body"],
"properties": {
"schema_version": { "type": "string", "pattern": "^v[0-9]+\\.[0-9]+$" },
"tenant_id": { "type": "string", "minLength": 1 },
"template_id": { "type": "string", "pattern": "^[A-Z0-9_-]{4,64}$" },
"channel": { "type": "string", "enum": ["email", "slack", "teams", "webhook", "sms"] },
"locale": { "type": "string", "pattern": "^[a-z]{2}(-[A-Z]{2})?$" },
"subject": { "type": "string" },
"body": { "type": "string" },
"helpers": { "type": "object", "additionalProperties": { "type": "string" } },
"merge_fields": { "type": "array", "items": { "type": "string" } },
"preview_hash": { "type": "string" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}

View File

@@ -0,0 +1,20 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://stella-ops.org/notify/schemas/webhook.schema.json",
"title": "Notify Webhook Payload",
"type": "object",
"required": ["schema_version", "tenant_id", "delivery_id", "signature", "body"],
"properties": {
"schema_version": { "type": "string", "pattern": "^v[0-9]+\\.[0-9]+$" },
"tenant_id": { "type": "string", "minLength": 1 },
"delivery_id": { "type": "string", "pattern": "^[0-9a-fA-F-]{18,36}$" },
"signature": { "type": "string" },
"hmac_id": { "type": "string" },
"body": { "type": "object" },
"sent_at": { "type": "string", "format": "date-time" },
"nonce": { "type": "string" },
"audience": { "type": "string" },
"expires_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}

View File

@@ -0,0 +1,6 @@
# Redaction and PII catalog (NR7)
- Classify merge fields: identifiers (hash), secrets (strip), PII (mask), operational metadata (retain).
- Storage and previews must use redacted forms by default; full bodies allowed only with `Notify.Audit` permission.
- Log payloads must omit secrets; hashes use BLAKE3-256 over UTF-8 normalized values.
- Fixtures under `docs/notifications/fixtures/redaction/` show expected redacted shapes for templates and receipts.

View File

@@ -0,0 +1,6 @@
# Tenant scoping and approvals (NR2)
- All Notify APIs require `tenant_id` in request and ledger records.
- High-impact actions (escalations, PII-bearing templates, cross-tenant fan-out) need N-of-M approvals: default 2 of 3 approvers with `Notify.Approver` role.
- Approvals captured as DSSE-signed records (future hook) and stored alongside rule change requests.
- Rejection reasons must be logged and returned in error payloads; audit log keeps requester, approver IDs, timestamps, and rule/template IDs.

View File

@@ -0,0 +1,6 @@
# Webhook and ack security (NR6)
- Webhooks must use HMAC-SHA256 with per-tenant rotating secrets or mTLS/DPoP. `hmac_id` maps to secret material.
- Ack URLs carry signed tokens (nonce, audience, tenant_id, delivery_id, expires_at) and are single-use. Reject replay or expired tokens.
- Enforce allowlists for domains and paths per tenant; deny wildcards.
- Capture failures in observability pipeline and DLQ with redrive after investigation.