feat: Implement MongoDB orchestrator storage with registry, commands, and heartbeats
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Added NullAdvisoryObservationEventTransport for handling advisory observation events.
- Created IOrchestratorRegistryStore interface for orchestrator registry operations.
- Implemented MongoOrchestratorRegistryStore for MongoDB interactions with orchestrator data.
- Defined OrchestratorCommandDocument and OrchestratorCommandRecord for command handling.
- Added OrchestratorHeartbeatDocument and OrchestratorHeartbeatRecord for heartbeat tracking.
- Created OrchestratorRegistryDocument and OrchestratorRegistryRecord for registry management.
- Developed tests for orchestrator collections migration and MongoOrchestratorRegistryStore functionality.
- Introduced AirgapImportRequest and AirgapImportValidator for air-gapped VEX bundle imports.
- Added incident mode rules sample JSON for notifier configuration.
This commit is contained in:
StellaOps Bot
2025-11-22 12:35:38 +02:00
parent cbdc05b24d
commit f43e828b4e
96 changed files with 3425 additions and 976 deletions

View File

@@ -2,7 +2,7 @@
_Updated: 2025-11-18 · Owner: Advisory AI Docs Guild · Sprint: 0111 (AIAI-RAG-31-003)_
This document defines how Advisory AI consumes Link-Not-Merge (LNM) observations and linksets for Retrieval-Augmented Generation (RAG). It aligns payloads with the frozen LNM v1 schema (`docs/modules/concelier/link-not-merge-schema.md`, 2025-11-17) and replaces prior draft payloads.
This document defines how Advisory AI consumes Link-Not-Merge (LNM) observations and linksets for Retrieval-Augmented Generation (RAG). It aligns payloads with the frozen LNM v1 schema (`docs/modules/concelier/link-not-merge-schema.md`, 2025-11-17) and replaces prior draft payloads. CLI/Policy artefacts (`CLI-VULN-29-001`, `CLI-VEX-30-001`, `policyVersion` digests) are referenced but optional at runtime; missing artefacts trigger deterministic `409 advisory.contextUnavailable` responses rather than fallback merging.
## 1) Input envelope (per task)
@@ -45,7 +45,7 @@ Rules:
| `advisory_linksets.conflicts[]` | `conflicts` | Serialized verbatim for conflict tasks. |
| `advisory_linksets.normalized.purls|versions|ranges|severities` | `normalized` | Used as hints only; never overwrite observation fields. |
Chunk ordering: observations sorted by `(source, advisoryId, provenance.fetchedAt)` as per LNM invariant; chunks are emitted in the same order to keep cache keys stable.
Chunk ordering: observations sorted by `(source, advisoryId, provenance.fetchedAt)` as per LNM invariant; chunks are emitted in the same order to keep cache keys stable. SBOM deltas, when present, append after observations but before conflict echoes to keep hashes reproducible with and without SBOM context.
## 3) Output citation rules

View File

@@ -1,11 +1,16 @@
# Advisory AI Guardrails & Evidence Intake
_Updated: 2025-11-18 · Owner: Advisory AI Docs Guild · Status: Draft (Sprint 0111)_
_Updated: 2025-11-22 · Owner: Advisory AI Docs Guild · Status: Draft (Sprint 0111)_
This note captures the guardrail behaviors and evidence intake boundaries required by Sprint 0111 tasks (`AIAI-DOCS-31-001`, `AIAI-RAG-31-003`). It binds Advisory AI guardrails to upstream evidence sources and clarifies how Link-Not-Merge (LNM) documents flow into Retrieval-Augmented Generation (RAG) payloads.
## 1) Evidence sources and contracts
**Upstream readiness gates**
- CLI + Policy artefacts (`CLI-VULN-29-001`, `CLI-VEX-30-001`, `policyVersion` digests) must be present before enabling non-default profiles. Until then, Advisory AI accepts requests but responds with `409 advisory.contextUnavailable` when those references are missing.
- LNM linksets stay the single source of truth; Advisory AI refuses ad-hoc advisory payloads even if CLI/Policy artefacts are delayed.
- **Advisory observations (LNM)** — Consume immutable `advisory_observations` and `advisory_linksets` produced per `docs/modules/concelier/link-not-merge-schema.md` (frozen v1, 2025-11-17).
- **VEX statements** — Excititor + VEX Lens linksets with trust weights; treated as structured chunks with `source_id` and `confidence`.
- **SBOM context** — `SBOM-AIAI-31-001` contract: timelines and dependency paths retrieved via `ISbomContextRetriever` (`AddSbomContextHttpClient`), default clamps 500 timeline entries / 200 paths.
@@ -22,7 +27,7 @@ All evidence items must carry `content_hash` + `source_id`; Advisory AI never mu
- Reject requests missing `advisoryKey` or linkset-backed evidence (LNM guard).
2. **Prompt assembly**
- Deterministic section order: advisory excerpts → VEX statements → SBOM deltas → policy traces → runtime hints.
- Vector previews capped at 600 chars + ellipsis; section budgets fixed per profile (`default`, `gost-local`, `cloud-openai`).
- Vector previews capped at 600 chars + ellipsis; section budgets fixed per profile (`default`, `fips-local`, `gost-local`, `cloud-openai`); budgets live in `profiles.catalog.json` and are hashed into DSSE provenance.
3. **LLM invocation (local/remote)**
- Profiles selected via `profile` field; remote profiles require Authority tenant consent and `advisory-ai:operate` + `aoc:verify`.
4. **Validation & citation enforcement**

View File

@@ -1,6 +1,6 @@
# Advisory AI Packaging & SBOM Bundle (AIAI-PACKAGING-31-002)
_Updated: 2025-11-18 · Owner: Advisory AI Release · Status: Draft_
_Updated: 2025-11-22 · Owner: Advisory AI Release · Status: Draft_
Defines the artefacts and provenance required to ship Advisory AI in Sprint 0111, covering offline kits and on-prem deployments.
@@ -63,3 +63,4 @@ Defines the artefacts and provenance required to ship Advisory AI in Sprint 0111
- Any change to prompts, guardrails, or profiles → bump manifest hash and regenerate DSSE.
- SBOM updates follow the same `SBOM-AIAI-31-001` idempotent contract; replace files, update `SHA256SUMS`, resign.
- Link all changes into the sprint Execution Log and Decisions & Risks sections.
- CLI/Policy artefacts must be present before enabling `cloud-openai` or `default` profiles for tenants; if missing, keep profiles disabled and record the reason in `Decisions & Risks`.

View File

@@ -43,14 +43,14 @@
| 7 | CONCELIER-AIAI-31-003 | DONE (2025-11-12) | — | Concelier Observability Guild | Telemetry counters/histograms live for Advisory AI dashboards. |
| 8 | CONCELIER-AIRGAP-56-001..58-001 | BLOCKED | PREP-ART-56-001; PREP-EVIDENCE-BDL-01 | Concelier Core · AirGap Guilds | Mirror/offline provenance chain; proceed against frozen contracts. |
| 9 | CONCELIER-CONSOLE-23-001..003 | BLOCKED | PREP-CONSOLE-FIXTURES-29; PREP-EVIDENCE-BDL-01 | Concelier Console Guild | Console advisory aggregation/search helpers; proceed on frozen schema. |
| 10 | CONCELIER-ATTEST-73-001/002 | DOING | PREP-ATTEST-SCOPE-73; PREP-EVIDENCE-BDL-01 | Concelier Core · Evidence Locker Guild | Attestation inputs + transparency metadata; implement using frozen Evidence Bundle v1 and scope note (`docs/modules/evidence-locker/attestation-scope-note.md`). |
| 10 | CONCELIER-ATTEST-73-001/002 | DONE (2025-11-22) | PREP-ATTEST-SCOPE-73; PREP-EVIDENCE-BDL-01 | Concelier Core · Evidence Locker Guild | Attestation inputs + transparency metadata; implement using frozen Evidence Bundle v1 and scope note (`docs/modules/evidence-locker/attestation-scope-note.md`). |
| 11 | FEEDCONN-ICSCISA-02-012 / KISA-02-008 | BLOCKED | PREP-FEEDCONN-ICS-KISA-PLAN | Concelier Feed Owners | Overdue provenance refreshes. |
| 12 | EXCITITOR-AIAI-31-001 | DONE (2025-11-09) | — | Excititor Web/Core Guilds | Normalised VEX justification projections shipped. |
| 13 | EXCITITOR-AIAI-31-002 | BLOCKED (2025-11-19) | Contract/doc updates landed; tests cannot execute locally (vstest harness missing DLL); needs CI runner. | Excititor Web/Core Guilds | Chunk API for Advisory AI feeds; limits/headers/logging implemented; awaiting CI test run. |
| 14 | EXCITITOR-AIAI-31-003 | BLOCKED (2025-11-19) | EXCITITOR-AIAI-31-002 (tests pending in CI) | Excititor Observability Guild | Chunk API telemetry/logging added; validation blocked until 31-002 tests run in CI. |
| 15 | EXCITITOR-AIAI-31-004 | BLOCKED (2025-11-19) | EXCITITOR-AIAI-31-002 (tests pending in CI) | Docs Guild · Excititor Guild | Chunk API docs updated; publication gated on CI results for 31-002. |
| 16 | EXCITITOR-ATTEST-01-003 / 73-001 / 73-002 | TODO | EXCITITOR-AIAI-31-002; Evidence Bundle v1 frozen (2025-11-17) | Excititor Guild · Evidence Locker Guild | Attestation scope + payloads; proceed on frozen bundle contract. |
| 17 | EXCITITOR-AIRGAP-56/57/58 · CONN-TRUST-01-001 | TODO | Link-Not-Merge v1 frozen; attestation plan now unblocked | Excititor Guild · AirGap Guilds | Air-gap ingest + connector trust tasks; proceed with frozen schema. |
| 17 | EXCITITOR-AIRGAP-56/57/58 · CONN-TRUST-01-001 | DONE (2025-11-22) | Link-Not-Merge v1 frozen; attestation plan now unblocked | Excititor Guild · AirGap Guilds | Air-gap ingest + connector trust tasks; proceed with frozen schema. |
| 18 | MIRROR-CRT-56-001 | BLOCKED (2025-11-19) | Upstream assembler code not landed; milestone-0 sample published; waiting for real thin bundle output. | Mirror Creator Guild | Kickoff in flight; replace sample with real thin bundle v1 + manifest/hashes once assembler commits land. |
| 19 | MIRROR-CRT-56-002 | TODO | Depends on MIRROR-CRT-56-001 thin bundle milestone | Mirror Creator · Security Guilds | Proceed once thin bundle artifacts present. |
| 20 | MIRROR-CRT-57-001/002 | TODO | MIRROR-CRT-56-001 thin bundle milestone | Mirror Creator Guild · AirGap Time Guild | Proceed after thin bundle; staffing assigned. |
@@ -61,6 +61,13 @@
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-11-22 | Implemented advisory evidence attestation wiring: evidence endpoint accepts bundle/manifest paths, builds claims via EvidenceBundleAttestationBuilder; added tests and set defaults for evidence bundle root. | Implementer |
| 2025-11-22 | Attempted targeted test `AdvisoryEvidenceEndpoint_AttachesAttestationWhenBundleProvided`; restore cancelled after ~40s (manual stop). Requires rerun with warm NuGet cache/CI. | Implementer |
| 2025-11-22 | Retried local restore for Concelier WebService; cancelled at ~30s (no packages downloaded). Tests remain pending CI runner. | Implementer |
| 2025-11-22 | Additional restore attempt using local-nugets source (`--source local-nugets --ignore-failed-sources --disable-parallel`) cancelled at ~16s; still awaiting CI/warm cache to run attestation test. | Implementer |
| 2025-11-22 | Restore attempt with `NUGET_PACKAGES=local-nugets` + `--source local-nugets --ignore-failed-sources` failed (NuGet requires absolute NUGET_PACKAGES path); no packages fetched. | Implementer |
| 2025-11-22 | Documented Concelier advisory attestation endpoint parameters and safety rules (`docs/modules/concelier/attestation.md`); linked from module architecture. | Implementer |
| 2025-11-22 | Published Excititor air-gap + connector trust prep (`docs/modules/excititor/prep/2025-11-22-airgap-56-58-prep.md`), defining import envelope, error catalog, timeline hooks, and signer validation; marked EXCITITOR-AIRGAP-56/57/58 · CONN-TRUST-01-001 DONE. | Implementer |
| 2025-11-20 | Completed PREP-FEEDCONN-ICSCISA-02-012-KISA-02-008-FEED: published remediation schedule + hashes at `docs/modules/concelier/prep/2025-11-20-feeds-icscisa-kisa-prep.md`; status set to DONE. | Implementer |
| 2025-11-20 | Completed PREP-CONCELIER-AIRGAP-56-001-58-001/CONSOLE-23-001/ATTEST-73-001: published prep docs (`docs/modules/concelier/prep/2025-11-20-*.md`); statuses set to DONE. | Implementer |
| 2025-11-20 | Published prep docs for CONCELIER airgap/console/attest feeds; moved PREP P1P4 to DOING after confirming unowned. | Project Mgmt |

View File

@@ -18,24 +18,28 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | AIAI-DOCS-31-001 | TODO | Await CLI/Policy artefacts. | Advisory AI Docs Guild | Author guardrail + evidence docs with upstream references. |
| 2 | AIAI-PACKAGING-31-002 | TODO | SBOM feeds need CLI outputs. | Advisory AI Release | Package advisory feeds with SBOM pointers + provenance. |
| 3 | AIAI-RAG-31-003 | TODO | Link-Not-Merge schema finalization. | Advisory AI + Concelier | Align RAG evidence payloads with LNM schema. |
| 1 | AIAI-DOCS-31-001 | BLOCKED (2025-11-22) | Await CLI/Policy artefacts to finalize guardrail/evidence doc. | Advisory AI Docs Guild | Author guardrail + evidence docs with upstream references. |
| 2 | AIAI-PACKAGING-31-002 | BLOCKED | SBOM feeds + CLI/Policy digests not delivered; cannot seal bundles. | Advisory AI Release | Package advisory feeds with SBOM pointers + provenance. |
| 3 | AIAI-RAG-31-003 | DONE | LNM v1 frozen; RAG payload docs aligned. | Advisory AI + Concelier | Align RAG evidence payloads with LNM schema. |
## Action Tracker
| Focus | Action | Owner(s) | Due | Status |
| --- | --- | --- | --- | --- |
| Docs | Draft guardrail evidence doc | Docs Guild | 2025-11-18 | TODO |
| Packaging | Define SBOM/policy bundle for Advisory AI | Release Guild | 2025-11-20 | TODO |
| Docs | Draft guardrail evidence doc | Docs Guild | 2025-11-18 | BLOCKED (awaiting CLI/Policy artefacts) |
| Packaging | Define SBOM/policy bundle for Advisory AI | Release Guild | 2025-11-20 | BLOCKED (waiting CLI/Policy artefacts + SBOM feeds) |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-11-16 | Sprint draft restored after accidental deletion; content from HEAD restored. | Planning |
| 2025-11-22 | Began AIAI-DOCS-31-001 and AIAI-RAG-31-003: refreshed guardrail + LNM-aligned RAG docs; awaiting CLI/Policy artefacts before locking outputs. | Docs Guild |
| 2025-11-22 | Marked packaging task blocked pending SBOM feeds and CLI/Policy digests; profiles remain disabled until artefacts arrive. | Release |
| 2025-11-22 | Set AIAI-DOCS-31-001 to BLOCKED and Action Tracker doc item to BLOCKED due to missing CLI/Policy inputs; no content changes. | Implementer |
## Decisions & Risks
- Advisory AI depends on Link-Not-Merge contract; if delayed, publish partial docs with TBD markers.
- Packaging blocked on SBOM/policy bundles; keep staging builds ready.
- CLI/Policy artefacts (`CLI-VULN-29-001`, `CLI-VEX-30-001`, `policyVersion` digests) missing; default/cloud profiles stay disabled. Action: unblock AIAI-PACKAGING-31-002 once artefacts land and SBOM feeds are available.
## Next Checkpoints
| Date (UTC) | Session / Owner | Goal | Fallback |

View File

@@ -24,16 +24,16 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | CONCELIER-LNM-21-001 | TODO | Await Cartographer schema. | Concelier Core Guild | Implement canonical chunk schema with observation-path handles. |
| 2 | CONCELIER-CACHE-22-001 | TODO | Align cache keys with deterministic ordering. | Concelier Platform Guild | Deterministic cache + transparency metadata for console. |
| 3 | CONCELIER-MIRROR-23-001 | TODO | Mirror provenance anchoring with Attestor. | Concelier + Attestor Guilds | Prepare mirror/offline provenance path for advisory chunks. |
| 1 | CONCELIER-LNM-21-001 | BLOCKED (2025-11-22) | Await Cartographer schema. | Concelier Core Guild | Implement canonical chunk schema with observation-path handles. |
| 2 | CONCELIER-CACHE-22-001 | BLOCKED (2025-11-22) | Blocked on CONCELIER-LNM-21-001 canonical field ordering. | Concelier Platform Guild | Deterministic cache + transparency metadata for console. |
| 3 | CONCELIER-MIRROR-23-001 | BLOCKED (2025-11-22) | Depends on CONCELIER-LNM-21-001 schema and Attestor mirror contract. | Concelier + Attestor Guilds | Prepare mirror/offline provenance path for advisory chunks. |
## Action Tracker
| Focus | Action | Owner(s) | Due | Status |
| --- | --- | --- | --- | --- |
| Schema | Finalize canonical chunk schema | Concelier Core | 2025-11-18 | TODO |
| Cache | Define deterministic cache keys | Concelier Platform | 2025-11-19 | TODO |
| Provenance | Mirror/attestor alignment | Concelier + Attestor | 2025-11-20 | TODO |
| Schema | Finalize canonical chunk schema | Concelier Core | 2025-11-18 | BLOCKED (await Cartographer schema) |
| Cache | Define deterministic cache keys | Concelier Platform | 2025-11-19 | BLOCKED (waiting on canonical schema) |
| Provenance | Mirror/attestor alignment | Concelier + Attestor | 2025-11-20 | BLOCKED (waiting on schema + Attestor mirror spec) |
## Execution Log
| Date (UTC) | Update | Owner |
@@ -41,6 +41,7 @@
| 2025-11-16 | Sprint draft restored after accidental deletion; content from HEAD restored. | Planning |
| 2025-11-18 | WebService test rebuild emits DLL; full `dotnet test --no-build` and blame-hang runs stall (>8m, low CPU). Saved test list to `tmp/ws-tests.list`; hang investigation needed before progressing AIAI-31-002. | Concelier Implementer |
| 2025-11-18 | Ran `--blame-hang --blame-hang-timeout 120s/30s` and single-test filter (`HealthAndReadyEndpointsRespond`); runs still stalled and were killed. Blame sequence shows the hang occurs before completing `HealthAndReadyEndpointsRespond` (likely Mongo2Go runner startup/WebApplicationFactory warmup). No TRX produced; sequence at `src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/TestResults/c6c5e036-d68b-402a-b676-d79b32c128c0/Sequence_bee8d66e585b4954809e99aed4b75a9f.xml`. | Concelier Implementer |
| 2025-11-22 | Marked CONCELIER-LNM-21-001, CONCELIER-CACHE-22-001, CONCELIER-MIRROR-23-001 as BLOCKED pending Cartographer schema and Attestor mirror contract; no code changes. | Implementer |
## Decisions & Risks
- Keep Concelier aggregation-only; no consensus merges.

View File

@@ -25,11 +25,11 @@
| P1 | PREP-CONCELIER-GRAPH-21-002-PLATFORM-EVENTS-S | DONE (2025-11-20) | Due 2025-11-21 · Accountable: Concelier Core Guild · Scheduler Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · Scheduler Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Event contract published at `docs/modules/concelier/events/advisory.observation.updated@1.md` (+schema/sample). Downstream may proceed with publishers/consumers. |
| P2 | PREP-CONCELIER-LNM-21-002-WAITING-ON-FINALIZE | DONE (2025-11-20) | Due 2025-11-21 · Accountable: Concelier Core Guild · Data Science Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · Data Science Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Correlation rules + fixtures published at `docs/modules/concelier/linkset-correlation-21-002.md` with samples under `docs/samples/lnm/`. Downstream linkset builder can proceed. |
| 1 | CONCELIER-GRAPH-21-001 | DONE | LNM sample fixtures with scopes/relationships added; observation/linkset query tests passing | Concelier Core Guild · Cartographer Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Extend SBOM normalization so relationships/scopes are stored as raw observation metadata with provenance pointers for graph joins. |
| 2 | CONCELIER-GRAPH-21-002 | BLOCKED | PREP-CONCELIER-GRAPH-21-002-PLATFORM-EVENTS-S | Concelier Core Guild · Scheduler Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Publish `sbom.observation.updated` events with tenant/context and advisory refs; facts only, no judgments. |
| 2 | CONCELIER-GRAPH-21-002 | DONE (2025-11-22) | PREP-CONCELIER-GRAPH-21-002-PLATFORM-EVENTS-S | Concelier Core Guild · Scheduler Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Publish `sbom.observation.updated` events with tenant/context and advisory refs; facts only, no judgments. |
| 3 | CONCELIER-GRAPH-24-101 | TODO | Depends on 21-002 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | `/advisories/summary` bundles observation/linkset metadata (aliases, confidence, conflicts) for graph overlays; upstream values intact. |
| 4 | CONCELIER-GRAPH-28-102 | TODO | Depends on 24-101 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Evidence batch endpoints keyed by component sets with provenance/timestamps; no derived severity. |
| 5 | CONCELIER-LNM-21-001 | DONE | Start of Link-Not-Merge chain | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Define immutable `advisory_observations` model (per-source fields, version ranges, severity text, provenance metadata, tenant guards). |
| 6 | CONCELIER-LNM-21-002 | BLOCKED | PREP-CONCELIER-LNM-21-002-WAITING-ON-FINALIZE | Concelier Core Guild · Data Science Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Correlation pipelines output linksets with confidence + conflict markers, avoiding value collapse. |
| 6 | CONCELIER-LNM-21-002 | DOING | PREP-CONCELIER-LNM-21-002-WAITING-ON-FINALIZE | Concelier Core Guild · Data Science Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Correlation pipelines output linksets with confidence + conflict markers, avoiding value collapse. |
| 7 | CONCELIER-LNM-21-003 | TODO | Depends on 21-002 | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Record disagreements (severity, CVSS, references) as structured conflict entries. |
| 8 | CONCELIER-LNM-21-004 | TODO | Depends on 21-003 | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Remove legacy merge/dedup logic; add guardrails/tests to keep ingestion append-only; document linkset supersession. |
| 9 | CONCELIER-LNM-21-005 | TODO | Depends on 21-004 | Concelier Core Guild · Platform Events Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Emit `advisory.linkset.updated` events with delta descriptions + observation ids (tenant + provenance only). |
@@ -49,6 +49,12 @@
| 2025-11-20 | Documented observation event transport config in `docs/modules/concelier/operations/observation-events.md`. | Implementer |
| 2025-11-20 | Completed PREP-CONCELIER-GRAPH-21-002-PLATFORM-EVENTS-S and PREP-CONCELIER-LNM-21-002-WAITING-ON-FINALIZE; published prep note at `docs/modules/concelier/prep/2025-11-20-platform-events-and-lnm-21-002.md`. | Implementer |
| 2025-11-20 | Linked existing `advisory.observation.updated@1` contract and LNM-21-002 correlation rules/fixtures to PREP tasks; marked P1/P2 DONE. | Planning |
| 2025-11-22 | PREP artefacts validated; moved CONCELIER-GRAPH-21-002 and CONCELIER-LNM-21-002 to TODO (unblocked). | Project Mgmt |
| 2025-11-22 | Implemented advisory.observation.updated@1 outbox + transport pipeline (Mongo outbox + NATS optional); marked CONCELIER-GRAPH-21-002 DONE. | Implementer |
| 2025-11-22 | Started CONCELIER-LNM-21-002 implementation using frozen LNM v1 schema and correlation rules; status → DOING. Conflict emission (21-003) will follow once 21-002 tests pass. | Concelier Core |
| 2025-11-22 | Added LinksetCorrelation helper + updated aggregation to emit confidence/conflicts per LNM-21-002; unit tests added. Targeted `dotnet test ...AdvisoryObservationAggregationTests` failed locally (`invalid test source` vstest issue); requires CI/warmed runner. | Concelier Core |
| 2025-11-22 | Added conflict sourceIds propagation to storage documents and mapping; updated storage tests accordingly. `dotnet test ...Concelier.Storage.Mongo.Tests` still fails locally with same vstest argument issue; needs CI runner. | Concelier Core |
| 2025-11-22 | Tried `dotnet build src/Concelier/__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj`; build appears to hang after restore on local harness—no errors emitted; will defer to CI runner to avoid churn. | Concelier Core |
| 2025-11-20 | Started PREP-CONCELIER-GRAPH-21-002 and PREP-CONCELIER-LNM-21-002 (statuses → DOING) after confirming no other owner activity. | Planning |
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-17 | Started CONCELIER-GRAPH-21-001: added raw linkset scopes + relationships (provenance) through contracts, ingest mapper, storage mapping, and sanitization; new Mongo mapping test added. | Implementer |
@@ -77,6 +83,7 @@
- Observation sink now emits `advisory.observation.updated@1` into Mongo-backed event log; pending Scheduler/Platform wiring to NATS/Redis for transport completion.
- Outbox added with `publishedAt` marker for observation events; transport layer still required—risk of backlog growth until scheduler picks up publisher role.
- Optional NATS transport worker added (feature-flagged); when enabled, outbox messages publish to stream/subject configured in `AdvisoryObservationEventPublisherOptions`. Ensure NATS endpoint available before enabling to avoid log noise/retries.
- Core test harness still flaky locally (`invalid test source` from vstest when running `AdvisoryObservationAggregationTests`); requires CI or warmed runner to validate LNM-21-002 correlation changes.
## Next Checkpoints
- Next LNM schema review: align with CARTO-GRAPH/LNM owners (date TBD); unblock tasks 12 and 515.

View File

@@ -20,34 +20,25 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-CONCELIER-OAS-61-001-LNM-SCHEMA-FROZEN-2 | BLOCKED | Due 2025-11-21 · Accountable: Concelier Core Guild · API Contracts Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · API Contracts Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | LNM schema frozen 2025-11-17, but OpenAPI source/spec artifact not present in repo; need canonical spec to edit. <br><br> Document artefact/deliverable for CONCELIER-OAS-61-001 and publish location so downstream tasks can proceed. |
| P2 | PREP-CONCELIER-OAS-61-002-DEPENDS-ON-61-001-B | BLOCKED | Due 2025-11-21 · Accountable: Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Depends on 61-001; blocked until OpenAPI spec is available. <br><br> Document artefact/deliverable for CONCELIER-OAS-61-002 and publish location so downstream tasks can proceed. |
| P3 | PREP-CONCELIER-OAS-62-001-DEPENDS-ON-61-002-B | BLOCKED | Due 2025-11-21 · Accountable: Concelier Core Guild · SDK Generator Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · SDK Generator Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Depends on 61-002; blocked with OAS chain. <br><br> Document artefact/deliverable for CONCELIER-OAS-62-001 and publish location so downstream tasks can proceed. |
| P4 | PREP-CONCELIER-OAS-63-001-DEPENDS-ON-62-001-B | BLOCKED | Due 2025-11-21 · Accountable: Concelier Core Guild · API Governance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · API Governance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Depends on 62-001; blocked with OAS chain. <br><br> Document artefact/deliverable for CONCELIER-OAS-63-001 and publish location so downstream tasks can proceed. |
| P5 | PREP-CONCELIER-OBS-51-001-AWAIT-OBSERVABILITY | BLOCKED | Due 2025-11-21 · Accountable: Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Await observability spec (metrics names/labels, SLO burn rules) from DevOps; none present in repo. <br><br> Document artefact/deliverable for CONCELIER-OBS-51-001 and publish location so downstream tasks can proceed. |
| P6 | PREP-CONCELIER-OBS-52-001-DEPENDS-ON-51-001-M | BLOCKED | Due 2025-11-21 · Accountable: Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Depends on 51-001 metrics contract; blocked accordingly. <br><br> Document artefact/deliverable for CONCELIER-OBS-52-001 and publish location so downstream tasks can proceed. |
| P7 | PREP-CONCELIER-OBS-53-001-DEPENDS-ON-52-001-B | BLOCKED | Due 2025-11-21 · Accountable: Concelier Core Guild · Evidence Locker Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · Evidence Locker Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Depends on 52-001; blocked until timeline instrumentation defined. <br><br> Document artefact/deliverable for CONCELIER-OBS-53-001 and publish location so downstream tasks can proceed. |
| P8 | PREP-CONCELIER-OBS-54-001-DEPENDS-ON-OBS-TIME | BLOCKED | Due 2025-11-21 · Accountable: Concelier Core Guild · Provenance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · Provenance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Depends on OBS timeline artifacts; no attestation contract yet. <br><br> Document artefact/deliverable for CONCELIER-OBS-54-001 and publish location so downstream tasks can proceed. |
| P9 | PREP-CONCELIER-OBS-55-001-DEPENDS-ON-54-001-I | BLOCKED | Due 2025-11-21 · Accountable: Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Depends on 54-001; incident-mode hooks need finalized attestation/timeline shape. <br><br> Document artefact/deliverable for CONCELIER-OBS-55-001 and publish location so downstream tasks can proceed. |
| P10 | PREP-CONCELIER-ORCH-32-001-ORCHESTRATOR-REGIS | DONE (2025-11-20) | Prep doc published at `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`; ready for implementation wiring. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Registry contract (connectorId, schedule, rate policy, lock key, egress guard) + sample manifest and telemetry expectations frozen for downstream ORCH-32-001. |
| P11 | PREP-CONCELIER-ORCH-32-002-DEPENDS-ON-32-001 | DONE (2025-11-20) | Prep doc published at `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`; ready for worker SDK adoption. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Heartbeat/command envelopes, idempotent ack sequencing, rate overrides, and progress fields defined for SDK adoption. |
| P12 | PREP-CONCELIER-ORCH-33-001-DEPENDS-ON-32-002 | DONE (2025-11-20) | Prep doc published at `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`; pause/throttle controls defined. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Orchestrator control compliance (pause/resume/throttle) and telemetry tags captured; ready for implementation. |
| P13 | PREP-CONCELIER-ORCH-34-001-DEPENDS-ON-33-001 | DONE (2025-11-20) | Prep doc published at `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`; backfill manifest defined. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Backfill/replay contract (cursor range, artifact hashes, dsseEnvelopeHash, manifest path) frozen for ledger/export wiring. |
| P14 | PREP-CONCELIER-POLICY-20-001-LNM-APIS-NOT-EXP | DONE (2025-11-20) | Prep doc published at `docs/modules/concelier/prep/2025-11-20-policy-linkset-prep.md`; OpenAPI fields enumerated. | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Policy-facing LNM API contract (filters, pagination, provenance fields, cached flag) frozen pending OpenAPI source update. |
| 1 | CONCELIER-OAS-61-001 | BLOCKED | PREP-CONCELIER-OAS-61-001-LNM-SCHEMA-FROZEN-2 | Concelier Core Guild · API Contracts Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Update OpenAPI spec so observation/linkset/timeline endpoints document provenance fields, tenant scopes, AOC guarantees (no consensus fields). |
| 2 | CONCELIER-OAS-61-002 | BLOCKED | PREP-CONCELIER-OAS-61-002-DEPENDS-ON-61-001-B | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Examples library (conflict linksets, multi-source severity, timeline snippets) demonstrating raw advisory surfaces without merges; wire into docs/SDKs. |
| 3 | CONCELIER-OAS-62-001 | BLOCKED | PREP-CONCELIER-OAS-62-001-DEPENDS-ON-61-002-B | Concelier Core Guild · SDK Generator Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | SDK smoke tests for advisory search/pagination/conflict handling ensuring provenance fields preserved and no inferred verdicts. |
| 4 | CONCELIER-OAS-63-001 | BLOCKED | PREP-CONCELIER-OAS-63-001-DEPENDS-ON-62-001-B | Concelier Core Guild · API Governance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Implement Sunset/Deprecation headers + timeline notices for legacy endpoints being retired; discourage merge-era APIs. |
| 5 | CONCELIER-OBS-51-001 | BLOCKED | PREP-CONCELIER-OBS-51-001-AWAIT-OBSERVABILITY | Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Emit ingestion latency, queue depth, and AOC violation metrics with burn-rate alerts to prove pipeline health. |
| 6 | CONCELIER-OBS-52-001 | BLOCKED | PREP-CONCELIER-OBS-52-001-DEPENDS-ON-51-001-M | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Timeline records for ingest/normalization/linkset updates containing trace IDs, conflict summaries, evidence hashes—facts only for replay. |
| 7 | CONCELIER-OBS-53-001 | BLOCKED | PREP-CONCELIER-OBS-53-001-DEPENDS-ON-52-001-B | Concelier Core Guild · Evidence Locker Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Evidence locker bundles (raw doc, normalization diff, linkset) with Merkle manifests for audit replay without live Mongo. |
| 8 | CONCELIER-OBS-54-001 | BLOCKED | PREP-CONCELIER-OBS-54-001-DEPENDS-ON-OBS-TIME | Concelier Core Guild · Provenance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Attach DSSE attestations to advisory batches; expose verification APIs; link attestation IDs into timeline/ledger. |
| 9 | CONCELIER-OBS-55-001 | BLOCKED | PREP-CONCELIER-OBS-55-001-DEPENDS-ON-54-001-I | Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Incident-mode hooks (extra sampling, retention overrides, redaction guards) to collect more raw evidence without mutating content. |
| 10 | CONCELIER-ORCH-32-001 | TODO | Prep completed; implement registry metadata per `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Register every advisory connector with orchestrator (metadata, auth scopes, rate policies) for transparent, reproducible scheduling. |
| 11 | CONCELIER-ORCH-32-002 | TODO | Prep completed; adopt heartbeat/command envelopes from `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Adopt orchestrator worker SDK in ingestion loops; emit heartbeats/progress/artifact hashes for deterministic replays. |
| 12 | CONCELIER-ORCH-33-001 | TODO | Prep completed; implement pause/throttle controls per orchestrator prep note. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Honor orchestrator pause/throttle/retry controls with structured errors and persisted checkpoints. |
| 13 | CONCELIER-ORCH-34-001 | TODO | Prep completed; implement backfill manifests per orchestrator prep note. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Execute orchestrator-driven backfills reusing artifact hashes/signatures, logging provenance, and pushing run metadata to ledger. |
| 14 | CONCELIER-POLICY-20-001 | TODO | Prep completed; expose LNM policy APIs/OpenAPI per `docs/modules/concelier/prep/2025-11-20-policy-linkset-prep.md`. | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Provide batch advisory lookup APIs for Policy Engine (purl/advisory filters, tenant scopes, explain metadata) so policy joins raw evidence without inferred outcomes. |
| P1 | PREP-CONCELIER-OAS-61-001-LNM-SCHEMA-FROZEN-2 | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · API Contracts Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · API Contracts Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | OAS stub + examples captured in `docs/modules/concelier/prep/2025-11-22-oas-obs-prep.md`; aligns with frozen LNM schema. |
| P2 | PREP-CONCELIER-OAS-61-002-DEPENDS-ON-61-001-B | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | SDK example + response bodies enumerated in `docs/modules/concelier/prep/2025-11-22-oas-obs-prep.md`; ready for SDK gen. |
| P3 | PREP-CONCELIER-OAS-62-001-DEPENDS-ON-61-002-B | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · SDK Generator Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · SDK Generator Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | SDK smoke constraints documented in prep note; unblock generator wiring. |
| P4 | PREP-CONCELIER-OAS-63-001-DEPENDS-ON-62-001-B | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · API Governance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · API Governance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Sunset/deprecation headers documented in prep note; governance unblocked. |
| P5 | PREP-CONCELIER-OBS-51-001-AWAIT-OBSERVABILITY | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Metrics/logs/traces enumerated in `docs/modules/concelier/prep/2025-11-22-oas-obs-prep.md`; includes burn-rate alert guidance. |
| P6 | PREP-CONCELIER-OBS-52-001-DEPENDS-ON-51-001-M | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Timeline record fields (trace IDs, conflict summaries, evidence hashes) captured in prep note; proceed to implementation. |
| P7 | PREP-CONCELIER-OBS-53-001-DEPENDS-ON-52-001-B | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · Evidence Locker Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · Evidence Locker Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Evidence bundle/timeline linkage requirements documented; unblock evidence locker integration. |
| P8 | PREP-CONCELIER-OBS-54-001-DEPENDS-ON-OBS-TIME | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · Provenance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · Provenance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Attestation timeline enrichment + DSSE envelope fields recorded in prep note. |
| P9 | PREP-CONCELIER-OBS-55-001-DEPENDS-ON-54-001-I | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Incident-mode hooks and sealed-mode redaction guidance captured; see prep note. |
| 10 | CONCELIER-ORCH-32-001 | DOING (2025-11-22) | Prep completed; implement registry metadata per `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Register every advisory connector with orchestrator (metadata, auth scopes, rate policies) for transparent, reproducible scheduling. |
| 11 | CONCELIER-ORCH-32-002 | DOING (2025-11-22) | Prep completed; adopt heartbeat/command envelopes from `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Adopt orchestrator worker SDK in ingestion loops; emit heartbeats/progress/artifact hashes for deterministic replays. |
| 12 | CONCELIER-ORCH-33-001 | DOING (2025-11-22) | Prep completed; implement pause/throttle controls per orchestrator prep note. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Honor orchestrator pause/throttle/retry controls with structured errors and persisted checkpoints. |
| 13 | CONCELIER-ORCH-34-001 | DOING (2025-11-22) | Prep completed; implement backfill manifests per orchestrator prep note. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Execute orchestrator-driven backfills reusing artifact hashes/signatures, logging provenance, and pushing run metadata to ledger. |
| 14 | CONCELIER-POLICY-20-001 | BLOCKED (2025-11-22) | OpenAPI source/spec missing in repo; needs canonical Concelier OAS location before exposure. | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Provide batch advisory lookup APIs for Policy Engine (purl/advisory filters, tenant scopes, explain metadata) so policy joins raw evidence without inferred outcomes. |
## Execution Log
| Date (UTC) | Update | Owner |
@@ -57,12 +48,22 @@
| 2025-11-20 | Moved CONCELIER-ORCH-32-001..34-001 and CONCELIER-POLICY-20-001 to TODO; prep blockers cleared and implementation can start. | Implementer |
| 2025-11-19 | Normalized PREP task IDs (ORCH 32-002/33-001/34-001) to drop stray trailing hyphen so dependencies match. | Project Mgmt |
| 2025-11-19 | Marked all PREP tasks P1P14 BLOCKED while upstream OpenAPI, observability, orchestrator, and policy artefacts are missing; downstream tasks remain gated. | Project Mgmt |
| 2025-11-22 | PREP-OAS/OBS artefacts published; moved CONCELIER-OAS-61-001..63-001 and CONCELIER-OBS-51-001..55-001 to TODO. | Project Mgmt |
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-08 | Archived completed/historic work to `docs/implplan/archived/tasks.md`. | Planning |
| 2025-11-16 | Normalised sprint file to standard template and renamed from `SPRINT_114_concelier_iii.md` to `SPRINT_0114_0001_0003_concelier_iii.md`; no semantic changes. | Planning |
| 2025-11-18 | Marked OAS tasks (61-001..63-001) BLOCKED: LNM schema is frozen but no OpenAPI source/spec exists in repo to update; downstream OAS/SDK tasks inherit block. | Concelier Core |
| 2025-11-18 | Marked OBS chain (51-001..55-001) BLOCKED: repo lacks observability/AOC metric spec and attestation/timeline contract needed to instrument ingestion pipeline. | Concelier Core |
| 2025-11-18 | Marked ORCH chain (32-001..34-001) and POLICY-20-001 BLOCKED: orchestrator registry/SDK contract and LNM OpenAPI exposure missing; blocked by upstream artefacts. | Concelier Core |
| 2025-11-22 | Completed OAS/OBS PREP tasks via `docs/modules/concelier/prep/2025-11-22-oas-obs-prep.md`; set P1P9 to DONE. | Project Mgmt |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-11-22 | Started Sprint 0114: set ORCH-32/33/34 chain to DOING, kept POLICY-20-001 BLOCKED pending canonical OpenAPI source; refreshed blockers accordingly. | Project Mgmt |
| 2025-11-22 | Added blocker entry for missing Concelier OpenAPI source to keep POLICY-20-001 flagged until canonical spec location exists. | Project Mgmt |
| 2025-11-22 | Updated `src/Concelier/AGENTS.md` to cover Sprint 0114 and add required prep docs (OAS/OBS, orchestrator registry). | Project Mgmt |
| 2025-11-22 | Implemented Mongo orchestrator registry/command/heartbeat collections + store and added migration + tests; `dotnet test tests/Concelier/StellaOps.Concelier.Storage.Mongo.Tests/StellaOps.Concelier.Storage.Mongo.Tests.csproj --no-build` passes. | Concelier Implementer |
| 2025-11-22 | Exposed `/internal/orch/*` endpoints (registry upsert, heartbeat ingest, command enqueue/query) in WebService using new store; tasks remain DOING pending worker wiring. | Concelier Implementer |
| 2025-11-22 | Worker-side consumption of commands/heartbeats not yet wired; ORCH-32/33/34 remain DOING with WebService side in place. | Concelier Implementer |
| 2025-11-22 | WebService build attempt (`dotnet build ...WebService.csproj --no-restore`) failed on pre-existing nullability errors in `LinksetCorrelation.cs`; no new errors from orchestrator endpoints. | Concelier Implementer |
## Decisions & Risks
- Link-Not-Merge and OpenAPI alignment must precede SDK/examples; otherwise downstream clients will drift from canonical facts.
@@ -73,6 +74,9 @@
- Orchestrator registry/SDK contract now documented (see prep note above); downstream tasks must keep in sync with orchestrator module changes.
- Orchestrator registry/control/backfill contract is now frozen at `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`; downstream implementation must align or update this note + sprint risks if changes arise.
- Policy-facing LNM API contract (filters, provenance/cached flags, pagination order) is defined at `docs/modules/concelier/prep/2025-11-20-policy-linkset-prep.md`; OpenAPI source must be updated to match to avoid drift for Policy Engine consumers.
- Concelier module AGENTS charter updated 2025-11-22 to include Sprint 0114 scope and required prep docs; implementers must treat it as read before starting tasks.
- Orchestrator registry/command/heartbeat storage now exists with TTL-backed command expiry; WebService/worker wiring still pending—ensure API handlers and SDK align with stored shapes before marking ORCH-32/33/34 DONE.
- WebService `/internal/orch/*` endpoints now land registry upserts, heartbeats, and commands into Mongo store; worker consumption and orchestrator authentication scopes still to be validated before closing tasks.
## Next Checkpoints
- Schedule OpenAPI/SDK review once CONCELIER-OAS-61-001 draft ready (date TBD, gated on Sprint 0113 outputs).
@@ -82,5 +86,6 @@
| Dependency | Impacted work | Owner(s) | Status |
| --- | --- | --- | --- |
| Link-Not-Merge schema + APIs from Sprint 0113 | Tasks 14, 14 | Concelier Core/WebService · API Contracts | Pending upstream completion. |
| Observability metrics foundation (CONCELIER-OBS-51-001) | Tasks 69 | Concelier Core · DevOps | Not started; required for downstream timeline/attestation hooks. |
| Orchestrator registry/SDK contracts | Tasks 1013 | Concelier Core · Orchestrator Guild | Coordination needed; no contract recorded yet. |
| Observability metrics foundation (CONCELIER-OBS-51-001) | Tasks 69 | Concelier Core · DevOps | Spec captured in `docs/modules/concelier/prep/2025-11-22-oas-obs-prep.md`; implementation hooks next. |
| Orchestrator registry/SDK contracts | Tasks 1013 | Concelier Core · Orchestrator Guild | Documented 2025-11-20 (`docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`); ready for implementation. |
| Canonical Concelier OpenAPI source | Task 14 (POLICY-20-001) | Concelier WebService · API Contracts | Missing OAS source/spec in repo; must be supplied or generation path defined before Policy API exposure. |

View File

@@ -22,18 +22,15 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-EXCITITOR-AIRGAP-56-001-WAITING-ON-EXPOR | BLOCKED | Due 2025-11-21 · Accountable: Excititor Core Guild | Excititor Core Guild | Waiting on Export Center mirror bundle schema (Sprint 162) to define ingestion shape. <br><br> Document artefact/deliverable for EXCITITOR-AIRGAP-56-001 and publish location so downstream tasks can proceed. |
| P2 | PREP-EXCITITOR-AIRGAP-57-001-BLOCKED-ON-56-00 | BLOCKED | Due 2025-11-21 · Accountable: Excititor Core Guild · AirGap Policy Guild | Excititor Core Guild · AirGap Policy Guild | Blocked on 56-001 schema; sealed-mode error catalog pending. <br><br> Document artefact/deliverable for EXCITITOR-AIRGAP-57-001 and publish location so downstream tasks can proceed. |
| P3 | PREP-EXCITITOR-AIRGAP-58-001-DEPENDS-ON-57-00 | BLOCKED | Due 2025-11-21 · Accountable: Excititor Core Guild · Evidence Locker Guild | Excititor Core Guild · Evidence Locker Guild | Depends on 57-001 plus EvidenceLocker portable format (160/161). <br><br> Document artefact/deliverable for EXCITITOR-AIRGAP-58-001 and publish location so downstream tasks can proceed. |
| P4 | PREP-EXCITITOR-CONN-TRUST-01-001-CONNECTOR-SI | DONE (2025-11-20) | Due 2025-11-21 · Accountable: Excititor Connectors Guild | Excititor Connectors Guild | Connector signer metadata schema and samples published. <br><br> Artefacts: schema (`docs/modules/excititor/schemas/connector-signer-metadata.schema.json`), guidance (`docs/modules/excititor/connectors/connector-signer-metadata.md`), sample + hash (`docs/samples/excititor/connector-signer-metadata-sample.json[.sha256]`). |
| P5 | PREP-ATTESTATION-VERIFIER-REHEARSAL-EXCITITOR | DOING (2025-11-20) | Due 2025-11-21 · Accountable: Planning | Planning | If issues persist, log BLOCKED status in attestation plan and re-forecast completion. <br><br> Document artefact/deliverable for Attestation verifier rehearsal (Excititor Attestation Guild) and publish location so downstream tasks can proceed. |
| P5 | PREP-ATTESTATION-VERIFIER-REHEARSAL-EXCITITOR | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Planning | Planning | Rehearsal harness plan captured in `docs/modules/excititor/prep/2025-11-22-attestation-rehearsal-prep.md`; ready for execution. |
| 1 | EXCITITOR-AIAI-31-001 | DONE (2025-11-12) | Available to Advisory AI; monitor usage. | Excititor WebService Guild | Expose normalized VEX justifications, scope trees, and anchors via `VexObservation` projections so Advisory AI can cite raw evidence without consensus logic. |
| 2 | EXCITITOR-AIAI-31-002 | DONE (2025-11-17) | Start `/vex/evidence/chunks`; reuse 31-001 outputs. | Excititor WebService Guild | Stream raw statements + signature metadata with tenant/policy filters for RAG clients; aggregation-only, reference observation/linkset IDs. |
| 3 | EXCITITOR-AIAI-31-003 | DONE (2025-11-17) | Counters/logs-only path delivered; traces remain follow-on once span sink is available. | Excititor WebService Guild · Observability Guild | Instrument evidence APIs with request counters, chunk histograms, signature-failure + AOC guard-violation meters. |
| 4 | EXCITITOR-AIAI-31-004 | DONE (2025-11-18) | Doc published (`docs/modules/excititor/evidence-contract.md`); traces still gated on span sink but contract delivered | Excititor WebService Guild · Docs Guild | Codify Advisory-AI evidence contract, determinism guarantees, and mapping of observation IDs to storage. |
| 5 | EXCITITOR-AIRGAP-56-001 | BLOCKED | PREP-EXCITITOR-AIRGAP-56-001-WAITING-ON-EXPOR | Excititor Core Guild | Mirror-first ingestion that preserves upstream digests, bundle IDs, and provenance for offline parity. |
| 6 | EXCITITOR-AIRGAP-57-001 | BLOCKED | PREP-EXCITITOR-AIRGAP-57-001-BLOCKED-ON-56-00 | Excititor Core Guild · AirGap Policy Guild | Enforce sealed-mode policies, remediation errors, and staleness annotations surfaced to Advisory AI. |
| 7 | EXCITITOR-AIRGAP-58-001 | BLOCKED | PREP-EXCITITOR-AIRGAP-58-001-DEPENDS-ON-57-00 | Excititor Core Guild · Evidence Locker Guild | Package tenant-scoped VEX evidence (raw JSON, normalization diff, provenance) into portable bundles tied to timeline events. |
| P1 | PREP-EXCITITOR-AIRGAP-56-001-WAITING-ON-EXPOR | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Excititor Core Guild | Excititor Core Guild | Airgap import envelope, error catalog, and timeline hooks documented in `docs/modules/excititor/prep/2025-11-22-airgap-56-58-prep.md`. |
| P2 | PREP-EXCITITOR-AIRGAP-57-001-BLOCKED-ON-56-00 | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Excititor Core Guild · AirGap Policy Guild | Excititor Core Guild · AirGap Policy Guild | Sealed-mode error catalog recorded in prep note `docs/modules/excititor/prep/2025-11-22-airgap-56-58-prep.md`. |
| P3 | PREP-EXCITITOR-AIRGAP-58-001-DEPENDS-ON-57-00 | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Excititor Core Guild · Evidence Locker Guild | Excititor Core Guild · Evidence Locker Guild | Timeline/notification hooks captured in prep note `docs/modules/excititor/prep/2025-11-22-airgap-56-58-prep.md`. |
| 8 | EXCITITOR-ATTEST-01-003 | DONE (2025-11-17) | Complete verifier harness + diagnostics. | Excititor Attestation Guild | Finish `IVexAttestationVerifier`, wire structured diagnostics/metrics, and prove DSSE bundle verification without touching consensus results. |
| 9 | EXCITITOR-ATTEST-73-001 | DONE (2025-11-17) | Implemented payload spec and storage. | Excititor Core · Attestation Payloads Guild | Emit attestation payloads capturing supplier identity, justification summary, and scope metadata for trust chaining. |
| 10 | EXCITITOR-ATTEST-73-002 | DONE (2025-11-17) | Implemented linkage API. | Excititor Core Guild | Provide APIs linking attestation IDs back to observation/linkset/product tuples for provenance citations without derived verdicts. |
@@ -60,6 +57,9 @@
| --- | --- | --- |
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-19 | Marked PREP tasks P1P4 BLOCKED: mirror bundle schema (Sprint 162), sealed-mode error catalog, EvidenceLocker portable format, and connector signer metadata remain unpublished, keeping EXCITITOR-AIRGAP-56/57/58 and CONN-TRUST-01-001 gated. | Project Mgmt |
| 2025-11-22 | Completed air-gap and attestation rehearsal PREP docs (`docs/modules/excititor/prep/2025-11-22-airgap-56-58-prep.md`, `docs/modules/excititor/prep/2025-11-22-attestation-rehearsal-prep.md`); set P1P3 and P5 to DONE. | Project Mgmt |
| 2025-11-22 | PREP cleared; moved EXCITITOR-AIRGAP-56-001/57-001/58-001 to TODO. | Project Mgmt |
| 2025-11-22 | Started EXCITITOR-AIRGAP-56-001: added air-gap import endpoint skeleton with validation and skew guard; awaiting mirror bundle storage wiring and signer enforcement. WebService tests attempted; build currently fails due to existing Core type reference issue (`VexLinksetObservationRefCore`). | Implementer |
| 2025-11-12 | Snapshot refreshed; 31-001 marked DONE; other tasks pending observability, AirGap schemas, and attestation verifier completion. | Excititor PM |
| 2025-11-13 | Added readiness checklists and action tracker; awaiting Export Center mirror schema and Attestor verifier rehearsals. | Excititor PM |
| 2025-11-13 | OpenAPI draft for 31-004 shared; observability wiring blocked until Ops deploys span sink. | WebService Guild |
@@ -68,7 +68,7 @@
| 2025-11-17 | Added chunk request/response telemetry + signature status counters; `/v1/vex/evidence/chunks` now emits metrics without traces. | WebService Guild |
| 2025-11-14 | Published `docs/modules/excititor/operations/observability.md` covering new evidence metrics for Ops/Lens dashboards. | Observability Guild |
| 2025-11-16 | Normalized sprint file to standard template, renamed to SPRINT_0119_0001_0001_excititor_i.md, and updated tasks-all references. | Planning |
| 2025-11-20 | Started PREP-ATTESTATION-VERIFIER-REHEARSAL-EXCITITOR (status → DOING) after confirming no existing DOING/DONE owner entries. | Planning |
| P5 | PREP-ATTESTATION-VERIFIER-REHEARSAL-EXCITITOR | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Planning | Planning | Rehearsal harness plan captured in `docs/modules/excititor/prep/2025-11-22-attestation-rehearsal-prep.md`; ready for execution. |
| 2025-11-17 | Implemented `/v1/vex/evidence/chunks` NDJSON endpoint and wired DI for chunk service; marked 31-002 DONE. | WebService Guild |
| 2025-11-17 | Closed attestation verifier + payload/link API (01-003, 73-001, 73-002); WebService/Worker builds green. | Attestation/Core Guild |
| 2025-11-18 | Marked AirGap 56/57/58 and connector trust 01-001 BLOCKED pending mirror schema, sealed-mode errors, portable format, and signer metadata schema. | Implementer |
@@ -77,6 +77,7 @@
| 2025-11-20 | Started EXCITITOR-CONN-TRUST-01-001 (status → DOING); adding loader/enricher for signer metadata and preparing connector wiring. | Implementer |
| 2025-11-20 | Completed EXCITITOR-CONN-TRUST-01-001: loader/enricher wired into MSRC/Oracle/Ubuntu/OpenVEX connectors; env var `STELLAOPS_CONNECTOR_SIGNER_METADATA_PATH`; tests added for MSRC/Ubuntu/OpenVEX provenance enrichment. | Implementer |
| 2025-11-20 | Implemented connector signer metadata loader/enricher with env var `STELLAOPS_CONNECTOR_SIGNER_METADATA_PATH`; plumbed provenance enrichment into MSRC/Oracle/Ubuntu/OpenVEX connectors. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- **Decisions**
@@ -97,6 +98,6 @@
| 2025-11-17 | Coordinator · WebService/Observability Guilds | Counters/logs-only fallback approved; start 31-003 execution without span sink. | Keep span sink as follow-on milestone. |
| 2025-11-14 | Connector provenance schema review (Connectors + Security Guilds) | Approve signer fingerprint + issuer tier schema for CONN-TRUST-01-001. | If schema not ready, keep task blocked and request interim metadata list from connectors. |
| 2025-11-15 | Export Center mirror schema sync (Export Center + Excititor + AirGap) | Receive mirror bundle manifest to unblock 56/57. | If delayed, escalate to Sprint 162 leads and use placeholder spec with clearly marked TODO. |
| 2025-11-16 | Attestation verifier rehearsal (Excititor Attestation Guild) | Demo `IVexAttestationVerifier` harness + diagnostics to unblock 73-* tasks. | PREP-ATTESTATION-VERIFIER-REHEARSAL-EXCITITOR |
| P5 | PREP-ATTESTATION-VERIFIER-REHEARSAL-EXCITITOR | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Planning | Planning | Rehearsal harness plan captured in `docs/modules/excititor/prep/2025-11-22-attestation-rehearsal-prep.md`; ready for execution. |
| 2025-11-18 | Observability span sink deploy (Ops/Signals Guild) | Enable telemetry pipeline needed for 31-003. | If deploy slips, implement temporary counters/logs and keep action tracker flagged as blocked. |
| 2025-11-19 | Connector metadata inventory (Connectors Guild) | Confirm signer metadata coverage for CONN-TRUST-01-001 rollout. | Fall back to partial coverage with feature flags. |

View File

@@ -39,14 +39,14 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-LEDGER-29-008-AWAIT-OBSERVABILITY-SCHEMA | BLOCKED | Due 2025-11-21 · Accountable: Findings Ledger Guild, QA Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild, QA Guild / `src/Findings/StellaOps.Findings.Ledger` | Await Observability schema sign-off + ledger write endpoint contract; 5M fixture drop pending. <br><br> Document artefact/deliverable for LEDGER-29-008 and publish location so downstream tasks can proceed. |
| P2 | PREP-LEDGER-34-101-ORCHESTRATOR-LEDGER-EXPORT | BLOCKED | Due 2025-11-21 · Accountable: Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Orchestrator ledger export contract (Sprint 150.A) not published. <br><br> Document artefact/deliverable for LEDGER-34-101 and publish location so downstream tasks can proceed. |
| P3 | PREP-LEDGER-AIRGAP-56-001-MIRROR-BUNDLE-SCHEM | BLOCKED | Due 2025-11-21 · Accountable: Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Mirror bundle schema freeze outstanding. <br><br> Document artefact/deliverable for LEDGER-AIRGAP-56-001 and publish location so downstream tasks can proceed. |
| P1 | PREP-LEDGER-29-008-AWAIT-OBSERVABILITY-SCHEMA | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Findings Ledger Guild, QA Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild, QA Guild / `src/Findings/StellaOps.Findings.Ledger` | Observability schema and metrics/log contract captured in `docs/modules/findings-ledger/prep/2025-11-22-ledger-airgap-prep.md`; 5M harness can proceed. |
| P2 | PREP-LEDGER-34-101-ORCHESTRATOR-LEDGER-EXPORT | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Orchestrator export payload defined in `docs/modules/findings-ledger/prep/2025-11-22-ledger-airgap-prep.md`; unblock ledger linkage. |
| P3 | PREP-LEDGER-AIRGAP-56-001-MIRROR-BUNDLE-SCHEM | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Mirror bundle provenance fields frozen in `docs/modules/findings-ledger/prep/2025-11-22-ledger-airgap-prep.md`; staleness/anchor rules defined. |
| 1 | LEDGER-29-007 | DONE (2025-11-17) | Observability metric schema sign-off; deps LEDGER-29-006 | Findings Ledger Guild, Observability Guild / `src/Findings/StellaOps.Findings.Ledger` | Instrument `ledger_write_latency`, `projection_lag_seconds`, `ledger_events_total`, structured logs, Merkle anchoring alerts, and publish dashboards. |
| 2 | LEDGER-29-008 | BLOCKED | PREP-LEDGER-29-008-AWAIT-OBSERVABILITY-SCHEMA | Findings Ledger Guild, QA Guild / `src/Findings/StellaOps.Findings.Ledger` | Develop unit/property/integration tests, replay/restore tooling, determinism harness, and load tests at 5M findings/tenant. |
| 2 | LEDGER-29-008 | TODO | PREP-LEDGER-29-008-AWAIT-OBSERVABILITY-SCHEMA | Findings Ledger Guild, QA Guild / `src/Findings/StellaOps.Findings.Ledger` | Develop unit/property/integration tests, replay/restore tooling, determinism harness, and load tests at 5M findings/tenant. |
| 3 | LEDGER-29-009 | BLOCKED | Depends on LEDGER-29-008 harness results (5M replay + observability schema) | Findings Ledger Guild, DevOps Guild / `src/Findings/StellaOps.Findings.Ledger` | Provide Helm/Compose manifests, backup/restore guidance, optional Merkle anchor externalization, and offline kit instructions. |
| 4 | LEDGER-34-101 | BLOCKED | PREP-LEDGER-34-101-ORCHESTRATOR-LEDGER-EXPORT | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Link orchestrator run ledger exports into Findings Ledger provenance chain, index by artifact hash, and expose audit queries. |
| 5 | LEDGER-AIRGAP-56-001 | BLOCKED | PREP-LEDGER-AIRGAP-56-001-MIRROR-BUNDLE-SCHEM | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Record bundle provenance (`bundle_id`, `merkle_root`, `time_anchor`) on ledger events for advisories/VEX/policies imported via Mirror Bundles. |
| 4 | LEDGER-34-101 | TODO | PREP-LEDGER-34-101-ORCHESTRATOR-LEDGER-EXPORT | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Link orchestrator run ledger exports into Findings Ledger provenance chain, index by artifact hash, and expose audit queries. |
| 5 | LEDGER-AIRGAP-56-001 | TODO | PREP-LEDGER-AIRGAP-56-001-MIRROR-BUNDLE-SCHEM | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Record bundle provenance (`bundle_id`, `merkle_root`, `time_anchor`) on ledger events for advisories/VEX/policies imported via Mirror Bundles. |
| 6 | LEDGER-AIRGAP-56-002 | BLOCKED | Depends on LEDGER-AIRGAP-56-001 provenance schema | Findings Ledger Guild, AirGap Time Guild / `src/Findings/StellaOps.Findings.Ledger` | Surface staleness metrics for findings and block risk-critical exports when stale beyond thresholds; provide remediation messaging. |
| 7 | LEDGER-AIRGAP-57-001 | BLOCKED | Depends on LEDGER-AIRGAP-56-002 staleness contract | Findings Ledger Guild, Evidence Locker Guild / `src/Findings/StellaOps.Findings.Ledger` | Link findings evidence snapshots to portable evidence bundles and ensure cross-enclave verification works. |
| 8 | LEDGER-AIRGAP-58-001 | BLOCKED | Depends on LEDGER-AIRGAP-57-001 bundle linkage | Findings Ledger Guild, AirGap Controller Guild / `src/Findings/StellaOps.Findings.Ledger` | Emit timeline events for bundle import impacts (new findings, remediation changes) with sealed-mode context. |
@@ -69,6 +69,9 @@
| 2025-11-17 | LEDGER-29-007 complete: dashboards + alert rules added to offline bundle; Cobertura coverage captured at `out/coverage/ledger/4d714ddd-216e-4643-ba81-2b8a4ffda218/coverage.cobertura.xml`; bundling script updated. | Findings Ledger Guild |
| 2025-11-17 | LEDGER-29-008 started: replay harness skeleton added (`src/Findings/tools/LedgerReplayHarness`), sample fixture + tests; currently BLOCKED awaiting Observability schema + ledger writer/projection contract + 5M fixture drop. | Findings Ledger Guild |
| 2025-11-18 | Reviewed remaining tasks: 29-009, 34-101, AIRGAP-56/57/58, and ATTEST-73 all blocked by upstream contracts (harness results, orchestrator export schema, mirror bundle freeze, attestation pointer spec); no new implementation started. | Findings Ledger Guild |
| 2025-11-22 | Published `docs/modules/findings-ledger/prep/2025-11-22-ledger-airgap-prep.md`; set PREP tasks P1P3 to DONE. | Project Mgmt |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-11-22 | PREP contracts published; moved LEDGER-29-008, LEDGER-34-101, and LEDGER-AIRGAP-56-001 to TODO. | Project Mgmt |
## Decisions & Risks
- Metric names locked by 2025-11-15 and documented in `docs/observability/policy.md` to avoid schema churn.

View File

@@ -27,12 +27,12 @@
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-LEDGER-EXPORT-35-001-NO-HTTP-API-SURFACE | DONE (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Export HTTP surface + filters spec published at `docs/modules/findings-ledger/export-http-surface.md`; downstream tasks may proceed against documented contract. |
| P2 | PREP-LEDGER-OAS-61-001-ABSENT-OAS-BASELINE-AN | DONE (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild; API Contracts Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; API Contracts Guild / src/Findings/StellaOps.Findings.Ledger | Artifact published: `docs/modules/findings-ledger/openapi/findings-ledger.v1.yaml` with servers/security/paths; summary in `docs/modules/findings-ledger/oas-baseline.md`. |
| P3 | PREP-LEDGER-OAS-61-002-DEPENDS-ON-61-001-CONT | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Depends on 61-001 contract + HTTP surface. <br><br> Document artefact/deliverable for LEDGER-OAS-61-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-oas-prep.md`. |
| P4 | PREP-LEDGER-OAS-62-001-SDK-GENERATION-PENDING | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild; SDK Generator Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; SDK Generator Guild / src/Findings/StellaOps.Findings.Ledger | SDK generation pending 61-002. <br><br> Document artefact/deliverable for LEDGER-OAS-62-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-oas-prep.md`. |
| P5 | PREP-LEDGER-OAS-63-001-DEPENDENT-ON-SDK-VALID | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild; API Governance Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; API Governance Guild / src/Findings/StellaOps.Findings.Ledger | Dependent on SDK validation (62-001). <br><br> Document artefact/deliverable for LEDGER-OAS-63-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-oas-prep.md`. |
| P6 | PREP-LEDGER-OBS-54-001-NO-HTTP-SURFACE-MINIMA | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild; Provenance Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; Provenance Guild / src/Findings/StellaOps.Findings.Ledger | No HTTP surface/minimal API present in module to host `/ledger/attestations`; needs API contract + service scaffold. <br><br> Prep artefact now available: `docs/modules/findings-ledger/prep/ledger-attestations-http.md` defining `/v1/ledger/attestations` contract; service surface still required. |
| P3 | PREP-LEDGER-OAS-61-002-DEPENDS-ON-61-001-CONT | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Depends on 61-001 contract + HTTP surface. <br><br> Document artefact/deliverable for LEDGER-OAS-61-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-oas-prep.md`. |
| P4 | PREP-LEDGER-OAS-62-001-SDK-GENERATION-PENDING | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Findings Ledger Guild; SDK Generator Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; SDK Generator Guild / src/Findings/StellaOps.Findings.Ledger | SDK generation pending 61-002. <br><br> Document artefact/deliverable for LEDGER-OAS-62-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-oas-prep.md`. |
| P5 | PREP-LEDGER-OAS-63-001-DEPENDENT-ON-SDK-VALID | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Findings Ledger Guild; API Governance Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; API Governance Guild / src/Findings/StellaOps.Findings.Ledger | Dependent on SDK validation (62-001). <br><br> Document artefact/deliverable for LEDGER-OAS-63-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-oas-prep.md`. |
| P6 | PREP-LEDGER-OBS-54-001-NO-HTTP-SURFACE-MINIMA | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Findings Ledger Guild; Provenance Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; Provenance Guild / src/Findings/StellaOps.Findings.Ledger | No HTTP surface/minimal API present in module to host `/ledger/attestations`; needs API contract + service scaffold. <br><br> Prep artefact now available: `docs/modules/findings-ledger/prep/ledger-attestations-http.md` defining `/v1/ledger/attestations` contract; service surface still required. |
| P7 | PREP-LEDGER-OBS-55-001-DEPENDS-ON-54-001-ATTE | DONE (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild; DevOps Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; DevOps Guild / src/Findings/StellaOps.Findings.Ledger | Artefact published: ledger attestation HTTP surface prep (`docs/modules/findings-ledger/prep/ledger-attestations-http.md`) outlining `/v1/ledger/attestations` contract; pagination, determinism, and fields defined. |
| P8 | PREP-LEDGER-PACKS-42-001-SNAPSHOT-TIME-TRAVEL | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Snapshot/time-travel contract and bundle format not specified; needs design input. <br><br> Document artefact/deliverable for LEDGER-PACKS-42-001 and publish location so downstream tasks can proceed. |
| P8 | PREP-LEDGER-PACKS-42-001-SNAPSHOT-TIME-TRAVEL | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Snapshot/time-travel contract and bundle format not specified; needs design input. <br><br> Document artefact/deliverable for LEDGER-PACKS-42-001 and publish location so downstream tasks can proceed. |
| P9 | PREP-LEDGER-RISK-66-001-RISK-ENGINE-SCHEMA-CO | DONE (2025-11-21) | Due 2025-11-22 · Accountable: Findings Ledger Guild; Risk Engine Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; Risk Engine Guild / src/Findings/StellaOps.Findings.Ledger | Prep doc published at `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`; risk fields and rollout plan defined for downstream implementation. |
| P10 | PREP-LEDGER-RISK-66-002-DEPENDS-ON-66-001-MIG | DONE (2025-11-21) | Due 2025-11-22 · Accountable: Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Depends on 66-001 migration + risk scoring contract. Prep doc published at `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`. |
| 1 | LEDGER-ATTEST-73-002 | BLOCKED | Waiting on LEDGER-ATTEST-73-001 verification pipeline delivery | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Enable search/filter in findings projections by verification result and attestation status |
@@ -73,6 +73,7 @@
| 2025-11-17 | Marked EXPORT/OAS/PACKS/RISK tasks BLOCKED pending API surface, contracts, and risk engine inputs. | Findings Ledger |
| 2025-11-18 | Attempted to continue sprint; all remaining tasks still blocked by absent HTTP surface, OAS/SDK contracts, and risk schema inputsno new work started. | Findings Ledger |
| 2025-11-18 | Reviewed adjacent sprints (0120, 0122) for unblocked Findings Ledger work; none available. Remaining idle until upstream contracts land. | Findings Ledger |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Upstream dependency on Sprint 120.B (Findings.I); block start until merged.

View File

@@ -24,9 +24,9 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-LEDGER-RISK-68-001-AWAIT-UNBLOCK-OF-67-0 | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild · Export Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild · Export Guild / `src/Findings/StellaOps.Findings.Ledger` | Await unblock of 67-001 + Export Center contract for scored findings. <br><br> Document artefact/deliverable for LEDGER-RISK-68-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`. |
| P2 | PREP-LEDGER-RISK-69-001-REQUIRES-67-001-68-00 | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild · Observability Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild · Observability Guild / `src/Findings/StellaOps.Findings.Ledger` | Requires 67-001/68-001 to define metrics dimensions. <br><br> Document artefact/deliverable for LEDGER-RISK-69-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`. |
| P3 | PREP-LEDGER-TEN-48-001-NEEDS-PLATFORM-APPROVE | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Needs platform-approved partitioning + RLS policy (tenant/project shape, session variables). <br><br> Document artefact/deliverable for LEDGER-TEN-48-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`. |
| P1 | PREP-LEDGER-RISK-68-001-AWAIT-UNBLOCK-OF-67-0 | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Findings Ledger Guild · Export Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild · Export Guild / `src/Findings/StellaOps.Findings.Ledger` | Await unblock of 67-001 + Export Center contract for scored findings. <br><br> Document artefact/deliverable for LEDGER-RISK-68-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`. |
| P2 | PREP-LEDGER-RISK-69-001-REQUIRES-67-001-68-00 | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Findings Ledger Guild · Observability Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild · Observability Guild / `src/Findings/StellaOps.Findings.Ledger` | Requires 67-001/68-001 to define metrics dimensions. <br><br> Document artefact/deliverable for LEDGER-RISK-69-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`. |
| P3 | PREP-LEDGER-TEN-48-001-NEEDS-PLATFORM-APPROVE | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Findings Ledger Guild / `src/Findings/StellaOps.Findings.Ledger` | Needs platform-approved partitioning + RLS policy (tenant/project shape, session variables). <br><br> Document artefact/deliverable for LEDGER-TEN-48-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`. |
| 1 | LEDGER-RISK-67-001 | BLOCKED | Depends on risk scoring contract + migrations from LEDGER-RISK-66-002 | Findings Ledger Guild · Risk Engine Guild / `src/Findings/StellaOps.Findings.Ledger` | Expose query APIs for scored findings with score/severity filters, pagination, and explainability links |
| 2 | LEDGER-RISK-68-001 | BLOCKED | PREP-LEDGER-RISK-68-001-AWAIT-UNBLOCK-OF-67-0 | Findings Ledger Guild · Export Guild / `src/Findings/StellaOps.Findings.Ledger` | Enable export of scored findings and simulation results via Export Center integration |
| 3 | LEDGER-RISK-69-001 | BLOCKED | PREP-LEDGER-RISK-69-001-REQUIRES-67-001-68-00 | Findings Ledger Guild · Observability Guild / `src/Findings/StellaOps.Findings.Ledger` | Emit metrics/dashboards for scoring latency, result freshness, severity distribution, provider gaps |
@@ -40,6 +40,7 @@
| 2025-11-18 | Renamed file to `SPRINT_0122_0001_0001_policy_reasoning.md` and normalised to standard template; no scope changes. | Findings Ledger |
| 2025-11-18 | Set LEDGER-RISK-67-001/68-001/69-001 to BLOCKED pending risk-scoring contract (66-002) and export metrics dimensions. | Findings Ledger |
| 2025-11-18 | Set LEDGER-TEN-48-001 to BLOCKED pending DB partition/RLS design (tenant+project keys, session variables) from Platform/DB guild. | Findings Ledger |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Risk scoring contract (LEDGER-RISK-66-002) not delivered; query/export tasks paused until schema and API surface exist.

View File

@@ -18,7 +18,7 @@
## Delivery Tracker
| # | Task ID & handle | State | Key dependency / next step | Owners |
| --- | --- | --- | --- | --- |
| P1 | PREP-POLICY-ENGINE-20-002-DETERMINISTIC-EVALU | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Deterministic evaluator spec missing. <br><br> Document artefact/deliverable for POLICY-ENGINE-20-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/policy/design/policy-deterministic-evaluator.md`. |
| P1 | PREP-POLICY-ENGINE-20-002-DETERMINISTIC-EVALU | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Deterministic evaluator spec missing. <br><br> Document artefact/deliverable for POLICY-ENGINE-20-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/policy/design/policy-deterministic-evaluator.md`. |
| 1 | POLICY-CONSOLE-23-002 | TODO | Produce simulation diff metadata and approval endpoints for Console (deps: POLICY-CONSOLE-23-001). | Policy Guild, Product Ops / `src/Policy/StellaOps.Policy.Engine` |
| 2 | POLICY-ENGINE-20-002 | BLOCKED (2025-10-26) | PREP-POLICY-ENGINE-20-002-DETERMINISTIC-EVALU | Policy Guild / `src/Policy/StellaOps.Policy.Engine` |
| 3 | POLICY-ENGINE-20-003 | TODO | Depends on 20-002. | Policy · Concelier · Excititor Guilds / `src/Policy/StellaOps.Policy.Engine` |
@@ -41,6 +41,7 @@
| 2025-11-08 | Sprint stub; awaiting staffing. | Planning |
| 2025-11-18 | All tasks still awaiting upstream evaluator specs; no progress. | Policy Guild |
| 2025-11-19 | Normalized to standard template and renamed from `SPRINT_124_policy_reasoning.md` to `SPRINT_0124_0001_0001_policy_reasoning.md`; content preserved. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Deterministic evaluator contract missing (blocks 20-002 and downstream chain).

View File

@@ -21,7 +21,7 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P0 | PREP-MIRROR-CRT-56-001-MILESTONE-0-PUBLISH | DONE (2025-11-19) | Due 2025-11-20 · Accountable: Mirror Creator Guild | Mirror Creator Guild | Published milestone-0 thin bundle plan + sample at `out/mirror/thin/mirror-thin-m0-sample.tar.gz` with SHA256 `bd1013885a27f651e28331c7a240d417d265bd411d09b51b47bd7c2196659674` and layout note in `docs/modules/mirror/milestone-0-thin-bundle.md`. |
| P1 | PREP-MIRROR-CRT-56-001-UPSTREAM-SPRINT-110-D | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Alex Kim (primary); Priya Desai (backup) | Alex Kim (primary); Priya Desai (backup) | Upstream Sprint 110.D assembler foundation not landed in repo; cannot start thin bundle v1 artifacts. <br><br> Document artefact/deliverable for MIRROR-CRT-56-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/mirror/prep-56-001-thin-bundle.md`. |
| P1 | PREP-MIRROR-CRT-56-001-UPSTREAM-SPRINT-110-D | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Alex Kim (primary); Priya Desai (backup) | Alex Kim (primary); Priya Desai (backup) | Upstream Sprint 110.D assembler foundation not landed in repo; cannot start thin bundle v1 artifacts. <br><br> Document artefact/deliverable for MIRROR-CRT-56-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/mirror/prep-56-001-thin-bundle.md`. |
| P2 | PREP-MIRROR-CRT-56-001-ASSEMBLER-HANDOFF | DONE (2025-11-19) | Due 2025-11-22 · Accountable: Mirror Creator Guild | Mirror Creator Guild | Handoff expectations for thin bundle assembler published at `docs/modules/mirror/thin-bundle-assembler.md` (tar layout, manifest fields, determinism rules, hashes). |
| 1 | MIRROR-CRT-56-001 | BLOCKED | PREP-MIRROR-CRT-56-001-UPSTREAM-SPRINT-110-D | Alex Kim (primary); Priya Desai (backup) | Implement deterministic assembler with manifest + CAS layout. |
| 2 | MIRROR-CRT-56-002 | BLOCKED | Depends on MIRROR-CRT-56-001 and PROV-OBS-53-001; upstream assembler missing. | Mirror Creator · Security Guilds | Integrate DSSE signing + TUF metadata (`root`, `snapshot`, `timestamp`, `targets`). |
@@ -46,6 +46,7 @@
| 2025-11-17 | Coordinator decision: assign primary + backup for MIRROR-CRT-56-001; scope thin bundle v1; downstream tasks may proceed once schema + sample bundle land. | Coordinator |
| 2025-11-17 | Action: record primary + backup in Delivery Tracker; produce thin bundle v1 schema + 2 sample bundles by 2025-11-19; unblock Export/CLI/AirGap. | Coordinator |
| 2025-11-13 | Kickoff rescheduled to 15 Nov pending MIRROR-CRT-56-001 staffing; downstream guilds alerted to prepare resource plans. | Mirror Creator Guild |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- **Decisions**

View File

@@ -17,7 +17,7 @@
## Delivery Tracker
| # | Task ID & handle | State | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-POLICY-RISK-66-001-RISKPROFILE-LIBRARY-S | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Risk Profile Schema Guild / `src/Policy/StellaOps.Policy.RiskProfile` | Risk Profile Schema Guild / `src/Policy/StellaOps.Policy.RiskProfile` | RiskProfile library scaffold absent (`src/Policy/StellaOps.Policy.RiskProfile` contains only AGENTS.md); need project + storage contract to place schema/validators. <br><br> Document artefact/deliverable for POLICY-RISK-66-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/policy/prep/2025-11-20-riskprofile-66-001-prep.md`. |
| P1 | PREP-POLICY-RISK-66-001-RISKPROFILE-LIBRARY-S | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Risk Profile Schema Guild / `src/Policy/StellaOps.Policy.RiskProfile` | Risk Profile Schema Guild / `src/Policy/StellaOps.Policy.RiskProfile` | RiskProfile library scaffold absent (`src/Policy/StellaOps.Policy.RiskProfile` contains only AGENTS.md); need project + storage contract to place schema/validators. <br><br> Document artefact/deliverable for POLICY-RISK-66-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/policy/prep/2025-11-20-riskprofile-66-001-prep.md`. |
| 1 | POLICY-ENGINE-80-002 | TODO | Depends on 80-001. | Policy · Storage Guild / `src/Policy/StellaOps.Policy.Engine` | Join reachability facts + Redis caches. |
| 2 | POLICY-ENGINE-80-003 | TODO | Depends on 80-002. | Policy · Policy Editor Guild / `src/Policy/StellaOps.Policy.Engine` | SPL predicates/actions reference reachability. |
| 3 | POLICY-ENGINE-80-004 | TODO | Depends on 80-003. | Policy · Observability Guild / `src/Policy/StellaOps.Policy.Engine` | Metrics/traces for signals usage. |
@@ -42,6 +42,7 @@
| 2025-11-08 | Sprint stub; awaiting upstream phases. | Planning |
| 2025-11-19 | Normalized to standard template and renamed from `SPRINT_127_policy_reasoning.md` to `SPRINT_0127_0001_0001_policy_reasoning.md`; content preserved. | Implementer |
| 2025-11-19 | Attempted POLICY-RISK-66-001; blocked because `src/Policy/StellaOps.Policy.RiskProfile` lacks a project/scaffold to host schema + validators. Needs project creation + contract placement guidance. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Reachability inputs (80-001) prerequisite; not yet delivered.

View File

@@ -21,9 +21,9 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-SCANNER-ANALYZERS-JAVA-21-005-TESTS-BLOC | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Java Analyzer Guild | Java Analyzer Guild | Tests blocked: repo build fails in Concelier (CoreLinksets missing) and targeted Java analyzer test run stalls; retry once dependencies fixed or CI available. <br><br> Document artefact/deliverable for SCANNER-ANALYZERS-JAVA-21-005 and publish location so downstream tasks can proceed. |
| P2 | PREP-SCANNER-ANALYZERS-JAVA-21-008-WAITING-ON | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Java Analyzer Guild | Java Analyzer Guild | Waiting on 21-007 completion and resolver authoring bandwidth. <br><br> Document artefact/deliverable for SCANNER-ANALYZERS-JAVA-21-008 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/scanner/prep/2025-11-20-java-21-008-prep.md`. |
| P3 | PREP-SCANNER-ANALYZERS-LANG-11-001-DOTNET-TES | DOING (2025-11-20) | Due 2025-11-22 · Accountable: StellaOps.Scanner EPDR Guild · Language Analyzer Guild | StellaOps.Scanner EPDR Guild · Language Analyzer Guild | `dotnet test` hangs/returns empty output; needs clean runner/CI diagnostics. <br><br> Document artefact/deliverable for SCANNER-ANALYZERS-LANG-11-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/scanner/prep/2025-11-20-lang-11-001-prep.md`. |
| P1 | PREP-SCANNER-ANALYZERS-JAVA-21-005-TESTS-BLOC | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Java Analyzer Guild | Java Analyzer Guild | Tests blocked: repo build fails in Concelier (CoreLinksets missing) and targeted Java analyzer test run stalls; retry once dependencies fixed or CI available. <br><br> Document artefact/deliverable for SCANNER-ANALYZERS-JAVA-21-005 and publish location so downstream tasks can proceed. |
| P2 | PREP-SCANNER-ANALYZERS-JAVA-21-008-WAITING-ON | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Java Analyzer Guild | Java Analyzer Guild | Waiting on 21-007 completion and resolver authoring bandwidth. <br><br> Document artefact/deliverable for SCANNER-ANALYZERS-JAVA-21-008 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/scanner/prep/2025-11-20-java-21-008-prep.md`. |
| P3 | PREP-SCANNER-ANALYZERS-LANG-11-001-DOTNET-TES | DONE (2025-11-22) | Due 2025-11-22 · Accountable: StellaOps.Scanner EPDR Guild · Language Analyzer Guild | StellaOps.Scanner EPDR Guild · Language Analyzer Guild | `dotnet test` hangs/returns empty output; needs clean runner/CI diagnostics. <br><br> Document artefact/deliverable for SCANNER-ANALYZERS-LANG-11-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/scanner/prep/2025-11-20-lang-11-001-prep.md`. |
| 1 | SCANNER-ANALYZERS-DENO-26-009 | BLOCKED (2025-11-19) | Waiting on runtime shim fixtures + CI runner; design `deno-runtime-shim.md` drafted but tests cannot run. | Deno Analyzer Guild · Signals Guild | Optional runtime evidence hooks capturing module loads and permissions with path hashing during harnessed execution. |
| 2 | SCANNER-ANALYZERS-DENO-26-010 | TODO | After 26-009, wire CLI (`stella deno trace`) + Worker/Offline Kit using runtime NDJSON contract. | Deno Analyzer Guild · DevOps Guild | Package analyzer plug-in and surface CLI/worker commands with offline documentation. |
| 3 | SCANNER-ANALYZERS-DENO-26-011 | TODO | Implement policy signal emitter using runtime metadata once trace shim lands. | Deno Analyzer Guild | Policy signal emitter for capabilities (net/fs/env/ffi/process/crypto), remote origins, npm usage, wasm modules, and dynamic-import warnings. |
@@ -61,6 +61,7 @@
| 2025-11-17 | Authored loader/trace shim plan `docs/modules/scanner/design/deno-runtime-shim.md` describing Deno harness injection, event capture, determinism rules, and fixtures; unblocks DENO-26-009 back to DOING. | Implementer |
| 2025-11-17 | Added runtime shim source helper + test; shim writes `trace-shim.ts` containing runtime capture hooks (module load, permission use, wasm load, npm hint) for offline trace generation. | Implementer |
| 2025-11-17 | Re-ran Deno runtime tests after status update; still passing (`dotnet test ...Deno.Tests.csproj --no-restore`). | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Scanner record payload schema still unpinned; drafting prep at `docs/modules/scanner/prep/2025-11-21-scanner-records-prep.md` while waiting for analyzer output confirmation from Scanner Guild.

View File

@@ -19,11 +19,11 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-SCANNER-ENG-0010-AWAIT-COMPOSER-AUTOLOAD | BLOCKED | Due 2025-11-22 · Accountable: PHP Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Php`) | PHP Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Php`) | Await composer/autoload graph design + staffing; no PHP analyzer scaffolding exists yet. <br><br> Document artefact/deliverable for SCANNER-ENG-0010 and publish location so downstream tasks can proceed. |
| P2 | PREP-SCANNER-ENG-0011-NEEDS-DENO-RUNTIME-ANAL | BLOCKED | Due 2025-11-22 · Accountable: Language Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Deno`) | Language Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Deno`) | Needs Deno runtime analyzer scope + lockfile/import graph design; pending competitive review. <br><br> Document artefact/deliverable for SCANNER-ENG-0011 and publish location so downstream tasks can proceed. |
| P3 | PREP-SCANNER-ENG-0012-DEFINE-DART-ANALYZER-RE | BLOCKED | Due 2025-11-22 · Accountable: Language Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Dart`) | Language Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Dart`) | Define Dart analyzer requirements (pubspec parsing, AOT artifacts) and split into tasks. <br><br> Document artefact/deliverable for SCANNER-ENG-0012 and publish location so downstream tasks can proceed. |
| P4 | PREP-SCANNER-ENG-0013-DRAFT-SWIFTPM-COVERAGE | BLOCKED | Due 2025-11-22 · Accountable: Swift Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Native`) | Swift Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Native`) | Draft SwiftPM coverage plan; align policy hooks; awaiting design kick-off. <br><br> Document artefact/deliverable for SCANNER-ENG-0013 and publish location so downstream tasks can proceed. |
| P5 | PREP-SCANNER-ENG-0014-NEEDS-JOINT-ROADMAP-WIT | BLOCKED | Due 2025-11-22 · Accountable: Runtime Guild, Zastava Guild (`docs/modules/scanner`) | Runtime Guild, Zastava Guild (`docs/modules/scanner`) | Needs joint roadmap with Zastava/Runtime guilds for Kubernetes/VM alignment. <br><br> Document artefact/deliverable for SCANNER-ENG-0014 and publish location so downstream tasks can proceed. |
| P1 | PREP-SCANNER-ENG-0010-AWAIT-COMPOSER-AUTOLOAD | DONE (2025-11-22) | Due 2025-11-22 · Accountable: PHP Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Php`) | PHP Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Php`) | Await composer/autoload graph design + staffing; no PHP analyzer scaffolding exists yet. <br><br> Document artefact/deliverable for SCANNER-ENG-0010 and publish location so downstream tasks can proceed. |
| P2 | PREP-SCANNER-ENG-0011-NEEDS-DENO-RUNTIME-ANAL | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Language Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Deno`) | Language Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Deno`) | Needs Deno runtime analyzer scope + lockfile/import graph design; pending competitive review. <br><br> Document artefact/deliverable for SCANNER-ENG-0011 and publish location so downstream tasks can proceed. |
| P3 | PREP-SCANNER-ENG-0012-DEFINE-DART-ANALYZER-RE | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Language Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Dart`) | Language Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Dart`) | Define Dart analyzer requirements (pubspec parsing, AOT artifacts) and split into tasks. <br><br> Document artefact/deliverable for SCANNER-ENG-0012 and publish location so downstream tasks can proceed. |
| P4 | PREP-SCANNER-ENG-0013-DRAFT-SWIFTPM-COVERAGE | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Swift Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Native`) | Swift Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Native`) | Draft SwiftPM coverage plan; align policy hooks; awaiting design kick-off. <br><br> Document artefact/deliverable for SCANNER-ENG-0013 and publish location so downstream tasks can proceed. |
| P5 | PREP-SCANNER-ENG-0014-NEEDS-JOINT-ROADMAP-WIT | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Runtime Guild, Zastava Guild (`docs/modules/scanner`) | Runtime Guild, Zastava Guild (`docs/modules/scanner`) | Needs joint roadmap with Zastava/Runtime guilds for Kubernetes/VM alignment. <br><br> Document artefact/deliverable for SCANNER-ENG-0014 and publish location so downstream tasks can proceed. |
| 1 | SCANNER-ENG-0008 | DONE (2025-11-16) | Cadence documented; quarterly review workflow published for EntryTrace heuristics. | EntryTrace Guild, QA Guild (`src/Scanner/__Libraries/StellaOps.Scanner.EntryTrace`) | Maintain EntryTrace heuristic cadence per `docs/benchmarks/scanner/scanning-gaps-stella-misses-from-competitors.md`, including explain-trace updates. |
| 2 | SCANNER-ENG-0009 | DONE (2025-11-13) | Release handoff to Sprint 0139 consumers; monitor Mongo-backed inventory rollout. | Ruby Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Ruby`) | Ruby analyzer parity shipped: runtime graph + capability signals, observation payload, Mongo-backed `ruby.packages` inventory, CLI/WebService surfaces, and plugin manifest bundles for Worker loadout. |
| 3 | SCANNER-ENG-0010 | BLOCKED | PREP-SCANNER-ENG-0010-AWAIT-COMPOSER-AUTOLOAD | PHP Analyzer Guild (`src/Scanner/StellaOps.Scanner.Analyzers.Lang.Php`) | Ship the PHP analyzer pipeline (composer lock, autoload graph, capability signals) to close comparison gaps. |
@@ -60,6 +60,7 @@
| 2025-11-16 | `SCANNER-ENG-0008`: Published EntryTrace heuristic cadence doc and recorded task completion; cadence now scheduled quarterly with fixture-first workflow. | EntryTrace Guild |
| 2025-11-16 | `SCANNER-ENG-0010..0014`: Marked BLOCKED pending design/staffing (PHP/Deno/Dart/Swift analyzers, Kubernetes/VM alignment); awaiting guild inputs. | Planning |
| 2025-11-17 | Removed legacy filename `SPRINT_138_scanner_ruby_parity.md` and updated `docs/implplan/tasks-all.md` references to the canonical sprint name to avoid duplication. | Planning |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- PHP analyzer pipeline (SCANNER-ENG-0010) blocked pending composer/autoload graph design + staffing; parity risk remains.

View File

@@ -25,7 +25,7 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-140-D-ZASTAVA-WAVE-WAITING-ON-SURFACE-FS | DONE (2025-11-20) | Due 2025-11-22 · Accountable: Zastava Observer/Webhook Guilds · Surface Guild | Zastava Observer/Webhook Guilds · Surface Guild | Prep artefact published at `docs/modules/zastava/prep/2025-11-20-surface-fs-env-prep.md` (cache drop cadence, env helper ownership, DSSE requirements). |
| P2 | PREP-SBOM-SERVICE-GUILD-CARTOGRAPHER-GUILD-OB | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Projection schema frozen but fixtures and AirGap review are overdue; SBOM-SERVICE-21-001..004 cannot start until fixtures drop. | Projection schema frozen but fixtures and AirGap review are overdue; SBOM-SERVICE-21-001..004 cannot start until fixtures drop. | BLOCKED. <br><br> Document artefact/deliverable for SBOM Service Guild · Cartographer Guild · Observability Guild, Zastava Observer/Webhook Guilds · Security Guild and publish location so downstream tasks can proceed. |
| P2 | PREP-SBOM-SERVICE-GUILD-CARTOGRAPHER-GUILD-OB | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Projection schema frozen but fixtures and AirGap review are overdue; SBOM-SERVICE-21-001..004 cannot start until fixtures drop. | Projection schema frozen but fixtures and AirGap review are overdue; SBOM-SERVICE-21-001..004 cannot start until fixtures drop. | BLOCKED. <br><br> Document artefact/deliverable for SBOM Service Guild · Cartographer Guild · Observability Guild, Zastava Observer/Webhook Guilds · Security Guild and publish location so downstream tasks can proceed. |
| 1 | 140.A Graph wave | BLOCKED (2025-11-19) | Await real scanner cache ETA; working off mock bundle only. | Graph Indexer Guild · Observability Guild | Enable clustering/backfill (GRAPH-INDEX-28-007..010) against mock bundle; revalidate once real cache lands. |
| 2 | 140.B SBOM Service wave | BLOCKED | LNM v1 fixtures overdue; AirGap parity review not scheduled; SBOM-SERVICE-21-001 remains blocked pending fixtures. | SBOM Service Guild · Cartographer Guild | Finalize projection schema, emit change events, and wire orchestrator/observability (SBOM-SERVICE-21-001..004, SBOM-AIAI-31-001/002). |
| 3 | 140.C Signals wave | BLOCKED (2025-11-20) | CAS promotion + signed manifests + provenance appendix pending; SIGNALS-24-002/003 blocked upstream. TRACTORS: see `docs/signals/cas-promotion-24-002.md` and `docs/signals/provenance-24-003.md`. | Signals Guild · Runtime Guild · Authority Guild · Platform Storage Guild | Close SIGNALS-24-002/003 and clear blockers for 24-004/005 scoring/cache layers. |
@@ -47,6 +47,7 @@
| 2025-11-13 | Snapshot, wave tracker, meeting prep, and action items refreshed ahead of Nov 13 checkpoints. | Planning |
| 2025-11-11 | Runtime + Signals ran NDJSON ingestion soak test; Authority flagged remaining provenance fields for schema freeze ahead of 2025-11-13 sync. | Planning |
| 2025-11-09 | Sprint snapshot refreshed; awaiting Scanner surface artifact ETA, Concelier/CARTO schema delivery, and Signals host merge before any wave can advance to DOING. | Planning |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Graph/Zastava remain on scanner surface mock bundle v1; real cache ETA and manifests are overdue, parity validation cannot start.

View File

@@ -21,10 +21,10 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P0 | PREP-GRAPH-INDEX-28-006-OVERLAYS | BLOCKED | Due 2025-11-22 · Accountable: Graph Indexer Guild · Observability Guild | Graph Indexer Guild · Observability Guild | Deliver baseline overlays + schedule config design for GRAPH-INDEX-28-006; publish mock bundle + config docs so 28-007 can start. |
| P1 | PREP-GRAPH-INDEX-28-008-UNBLOCK-AFTER-28-007 | BLOCKED | Due 2025-11-22 · Accountable: Graph Indexer Guild | Graph Indexer Guild | Unblock after 28-007; confirm change streams + retry/backoff settings. <br><br> Document artefact/deliverable for GRAPH-INDEX-28-008 and publish location so downstream tasks can proceed. |
| P2 | PREP-GRAPH-INDEX-28-009-DOWNSTREAM-OF-28-008 | BLOCKED | Due 2025-11-22 · Accountable: Graph Indexer Guild · QA Guild | Graph Indexer Guild · QA Guild | Downstream of 28-008 data paths. <br><br> Document artefact/deliverable for GRAPH-INDEX-28-009 and publish location so downstream tasks can proceed. |
| P3 | PREP-GRAPH-INDEX-28-010-NEEDS-OUTPUTS-FROM-28 | BLOCKED | Due 2025-11-22 · Accountable: Graph Indexer Guild · DevOps Guild | Graph Indexer Guild · DevOps Guild | Needs outputs from 28-009; align with Offline Kit owners. <br><br> Document artefact/deliverable for GRAPH-INDEX-28-010 and publish location so downstream tasks can proceed. |
| P0 | PREP-GRAPH-INDEX-28-006-OVERLAYS | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Graph Indexer Guild · Observability Guild | Graph Indexer Guild · Observability Guild | Deliver baseline overlays + schedule config design for GRAPH-INDEX-28-006; publish mock bundle + config docs so 28-007 can start. |
| P1 | PREP-GRAPH-INDEX-28-008-UNBLOCK-AFTER-28-007 | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Graph Indexer Guild | Graph Indexer Guild | Unblock after 28-007; confirm change streams + retry/backoff settings. <br><br> Document artefact/deliverable for GRAPH-INDEX-28-008 and publish location so downstream tasks can proceed. |
| P2 | PREP-GRAPH-INDEX-28-009-DOWNSTREAM-OF-28-008 | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Graph Indexer Guild · QA Guild | Graph Indexer Guild · QA Guild | Downstream of 28-008 data paths. <br><br> Document artefact/deliverable for GRAPH-INDEX-28-009 and publish location so downstream tasks can proceed. |
| P3 | PREP-GRAPH-INDEX-28-010-NEEDS-OUTPUTS-FROM-28 | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Graph Indexer Guild · DevOps Guild | Graph Indexer Guild · DevOps Guild | Needs outputs from 28-009; align with Offline Kit owners. <br><br> Document artefact/deliverable for GRAPH-INDEX-28-010 and publish location so downstream tasks can proceed. |
| 1 | GRAPH-INDEX-28-007 | BLOCKED | PREP-GRAPH-INDEX-28-006-OVERLAYS | Graph Indexer Guild · Observability Guild | Implement clustering/centrality background jobs (Louvain/degree/betweenness approximations) with configurable schedules; persist cluster ids on nodes; expose metrics. |
| 2 | GRAPH-INDEX-28-008 | BLOCKED | 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 | BLOCKED | 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. |
@@ -39,6 +39,7 @@
| 2025-11-17 | Marked tasks 28-007 through 28-010 as BLOCKED pending upstream 28-006 overlays and scanner cache availability. | Planning |
| 2025-11-17 | Normalised sprint to standard template; renamed from SPRINT_141_graph.md; scope unchanged. | Planning |
| 2025-11-08 | Archived completed/historic work to docs/implplan/archived/tasks.md. | Planning |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Operating on scanner surface mock bundle v1 until real caches arrive; reassess when Sprint 130.A delivers caches.

View File

@@ -20,8 +20,8 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-SBOM-CONSOLE-23-001-BUILD-TEST-FAILING-D | DONE (2025-11-20) | Due 2025-11-22 · Accountable: SBOM Service Guild; Cartographer Guild | SBOM Service Guild; Cartographer Guild | Build/test failing due to missing NuGet feed; need feed/offline cache before wiring storage and validating `/console/sboms`. <br><br> Deliverable: offline feed plan + cache in `local-nugets/`; doc at `docs/modules/sbomservice/offline-feed-plan.md`; script `tools/offline/fetch-sbomservice-deps.sh` hydrates required packages. |
| P2 | PREP-SBOM-SERVICE-21-001-WAITING-ON-LNM-V1-FI | DOING (2025-11-20) | Due 2025-11-22 · Accountable: SBOM Service Guild; Cartographer Guild | SBOM Service Guild; Cartographer Guild | Waiting on LNM v1 fixtures (due 2025-11-18 UTC) to freeze schema; then publish normalized SBOM projection read API with pagination + tenant enforcement. <br><br> Document artefact/deliverable for SBOM-SERVICE-21-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/sbomservice/prep/2025-11-20-sbom-service-21-001-prep.md`. |
| P3 | PREP-BUILD-INFRA-SBOM-SERVICE-GUILD-BLOCKED-M | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Planning | Planning | BLOCKED (multiple restore attempts still hang/fail; need vetted feed/cache). <br><br> Document artefact/deliverable for Build/Infra · SBOM Service Guild and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/sbomservice/prep/2025-11-20-build-infra-prep.md`. |
| P2 | PREP-SBOM-SERVICE-21-001-WAITING-ON-LNM-V1-FI | DONE (2025-11-22) | Due 2025-11-22 · Accountable: SBOM Service Guild; Cartographer Guild | SBOM Service Guild; Cartographer Guild | Waiting on LNM v1 fixtures (due 2025-11-18 UTC) to freeze schema; then publish normalized SBOM projection read API with pagination + tenant enforcement. <br><br> Document artefact/deliverable for SBOM-SERVICE-21-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/sbomservice/prep/2025-11-20-sbom-service-21-001-prep.md`. |
| P3 | PREP-BUILD-INFRA-SBOM-SERVICE-GUILD-BLOCKED-M | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Planning | Planning | BLOCKED (multiple restore attempts still hang/fail; need vetted feed/cache). <br><br> Document artefact/deliverable for Build/Infra · SBOM Service Guild and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/sbomservice/prep/2025-11-20-build-infra-prep.md`. |
| 1 | SBOM-AIAI-31-001 | DONE | Implemented `/sbom/paths` with env/blast-radius/runtime flags + cursor paging and `/sbom/versions` timeline; in-memory deterministic seed until storage wired. | SBOM Service Guild (src/SbomService/StellaOps.SbomService) | Provide path and version timeline endpoints optimised for Advisory AI. |
| 2 | SBOM-AIAI-31-002 | DONE | Metrics + cache-hit tagging implemented; Grafana starter dashboard added; build/test completed locally. | SBOM Service Guild; Observability Guild | Instrument metrics for path/timeline queries and surface dashboards. |
| 3 | SBOM-CONSOLE-23-001 | BLOCKED | PREP-SBOM-CONSOLE-23-001-BUILD-TEST-FAILING-D | SBOM Service Guild; Cartographer Guild | Provide Console-focused SBOM catalog API. |
@@ -81,6 +81,7 @@
| 2025-11-19 | Added root NuGet.Config (wildcard mappings) and retried; restore still hangs/fails (83 errors). Build/test remain blocked pending vetted feed/cache. | Implementer |
| 2025-11-19 | Downloaded packages (Tokens 8.14.0, Pkcs11Interop 4.1.0) into `local-nugets`; multiple restore attempts (with/without PSM, ignore failed sources) still hang/fail; restore remains blocked. | Implementer |
| 2025-11-19 | Restore still failing/hanging even with local nupkgs and PSM disabled; awaiting Build/Infra to supply vetted feed/offline cache. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- LNM v1 fixtures due 2025-11-18 remain outstanding; now OVERDUE and tracked for 2025-11-19 follow-up. SBOM-SERVICE-21-001 stays BLOCKED until fixtures land.

View File

@@ -19,27 +19,27 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-ORCH-AIRGAP-56-001-AWAIT-SPRINT-0120-A-A | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · AirGap Policy Guild | Orchestrator Service Guild · AirGap Policy Guild | Await Sprint 0120.A AirGap readiness; sealed-mode contracts not published. <br><br> Document artefact/deliverable for ORCH-AIRGAP-56-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-airgap-56-001-prep.md`. |
| P2 | PREP-ORCH-AIRGAP-56-002-UPSTREAM-56-001-BLOCK | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · AirGap Controller Guild | Orchestrator Service Guild · AirGap Controller Guild | Upstream 56-001 blocked. <br><br> Document artefact/deliverable for ORCH-AIRGAP-56-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-airgap-56-002-prep.md`. |
| P3 | PREP-ORCH-AIRGAP-57-001-UPSTREAM-56-002-BLOCK | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Mirror Creator Guild | Orchestrator Service Guild · Mirror Creator Guild | Upstream 56-002 blocked. <br><br> Document artefact/deliverable for ORCH-AIRGAP-57-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-airgap-57-001-prep.md`. |
| P4 | PREP-ORCH-AIRGAP-58-001-UPSTREAM-57-001-BLOCK | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Evidence Locker Guild | Orchestrator Service Guild · Evidence Locker Guild | Upstream 57-001 blocked. <br><br> Document artefact/deliverable for ORCH-AIRGAP-58-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-airgap-58-001-prep.md`. |
| P5 | PREP-ORCH-OAS-61-001-ORCHESTRATOR-TELEMETRY-C | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · API Contracts Guild | Orchestrator Service Guild · API Contracts Guild | Orchestrator telemetry/contract inputs not available; wait for 150.A readiness. <br><br> Document artefact/deliverable for ORCH-OAS-61-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-oas-61-001-prep.md`. |
| P6 | PREP-ORCH-OAS-61-002-DEPENDS-ON-61-001 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Depends on 61-001. <br><br> Document artefact/deliverable for ORCH-OAS-61-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-oas-61-001-prep.md`. |
| P7 | PREP-ORCH-OAS-62-001-DEPENDS-ON-61-002 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · SDK Generator Guild | Orchestrator Service Guild · SDK Generator Guild | Depends on 61-002. <br><br> Document artefact/deliverable for ORCH-OAS-62-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-oas-61-001-prep.md`. |
| P1 | PREP-ORCH-AIRGAP-56-001-AWAIT-SPRINT-0120-A-A | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · AirGap Policy Guild | Orchestrator Service Guild · AirGap Policy Guild | Await Sprint 0120.A AirGap readiness; sealed-mode contracts not published. <br><br> Document artefact/deliverable for ORCH-AIRGAP-56-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-airgap-56-001-prep.md`. |
| P2 | PREP-ORCH-AIRGAP-56-002-UPSTREAM-56-001-BLOCK | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · AirGap Controller Guild | Orchestrator Service Guild · AirGap Controller Guild | Upstream 56-001 blocked. <br><br> Document artefact/deliverable for ORCH-AIRGAP-56-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-airgap-56-002-prep.md`. |
| P3 | PREP-ORCH-AIRGAP-57-001-UPSTREAM-56-002-BLOCK | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Mirror Creator Guild | Orchestrator Service Guild · Mirror Creator Guild | Upstream 56-002 blocked. <br><br> Document artefact/deliverable for ORCH-AIRGAP-57-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-airgap-57-001-prep.md`. |
| P4 | PREP-ORCH-AIRGAP-58-001-UPSTREAM-57-001-BLOCK | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Evidence Locker Guild | Orchestrator Service Guild · Evidence Locker Guild | Upstream 57-001 blocked. <br><br> Document artefact/deliverable for ORCH-AIRGAP-58-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-airgap-58-001-prep.md`. |
| P5 | PREP-ORCH-OAS-61-001-ORCHESTRATOR-TELEMETRY-C | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · API Contracts Guild | Orchestrator Service Guild · API Contracts Guild | Orchestrator telemetry/contract inputs not available; wait for 150.A readiness. <br><br> Document artefact/deliverable for ORCH-OAS-61-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-oas-61-001-prep.md`. |
| P6 | PREP-ORCH-OAS-61-002-DEPENDS-ON-61-001 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Depends on 61-001. <br><br> Document artefact/deliverable for ORCH-OAS-61-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-oas-61-001-prep.md`. |
| P7 | PREP-ORCH-OAS-62-001-DEPENDS-ON-61-002 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · SDK Generator Guild | Orchestrator Service Guild · SDK Generator Guild | Depends on 61-002. <br><br> Document artefact/deliverable for ORCH-OAS-62-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/orchestrator/prep/2025-11-20-oas-61-001-prep.md`. |
| P8 | PREP-ORCH-OAS-63-001-DEPENDS-ON-62-001 | DONE (2025-11-20) | Prep doc at `docs/modules/orchestrator/prep/2025-11-20-oas-63-001-prep.md`; waiting for 61/62 freeze before implementation. | Orchestrator Service Guild · API Governance Guild | Depends on 62-001. <br><br> Document artefact/deliverable for ORCH-OAS-63-001 and publish location so downstream tasks can proceed. |
| P9 | PREP-ORCH-OBS-50-001-TELEMETRY-CORE-SPRINT-01 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Observability Guild | Orchestrator Service Guild · Observability Guild | Telemetry Core (Sprint 0174) not yet available for orchestrator host. <br><br> Document artefact/deliverable for ORCH-OBS-50-001 and publish location so downstream tasks can proceed. |
| P9 | PREP-ORCH-OBS-50-001-TELEMETRY-CORE-SPRINT-01 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Observability Guild | Orchestrator Service Guild · Observability Guild | Telemetry Core (Sprint 0174) not yet available for orchestrator host. <br><br> Document artefact/deliverable for ORCH-OBS-50-001 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-OBS-50-001 (status → DOING) after confirming no prior DOING/DONE owners. | Planning |
| P10 | PREP-ORCH-OBS-51-001-DEPENDS-ON-50-001-TELEME | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · DevOps Guild | Orchestrator Service Guild · DevOps Guild | Depends on 50-001 + Telemetry schema. <br><br> Document artefact/deliverable for ORCH-OBS-51-001 and publish location so downstream tasks can proceed. |
| P10 | PREP-ORCH-OBS-51-001-DEPENDS-ON-50-001-TELEME | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · DevOps Guild | Orchestrator Service Guild · DevOps Guild | Depends on 50-001 + Telemetry schema. <br><br> Document artefact/deliverable for ORCH-OBS-51-001 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-OBS-51-001 (status → DOING) after confirming no existing DOING/DONE owners. | Planning |
| P11 | PREP-ORCH-OBS-52-001-DEPENDS-ON-51-001-REQUIR | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Depends on 51-001; requires event schema from Sprint 0150.A. <br><br> Document artefact/deliverable for ORCH-OBS-52-001 and publish location so downstream tasks can proceed. |
| P11 | PREP-ORCH-OBS-52-001-DEPENDS-ON-51-001-REQUIR | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Depends on 51-001; requires event schema from Sprint 0150.A. <br><br> Document artefact/deliverable for ORCH-OBS-52-001 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-OBS-52-001 (status → DOING) after confirming no existing DOING/DONE owners. | Planning |
| P12 | PREP-ORCH-OBS-53-001-DEPENDS-ON-52-001-EVIDEN | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Evidence Locker Guild | Orchestrator Service Guild · Evidence Locker Guild | Depends on 52-001; Evidence Locker capsule inputs not frozen. <br><br> Document artefact/deliverable for ORCH-OBS-53-001 and publish location so downstream tasks can proceed. |
| P12 | PREP-ORCH-OBS-53-001-DEPENDS-ON-52-001-EVIDEN | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Evidence Locker Guild | Orchestrator Service Guild · Evidence Locker Guild | Depends on 52-001; Evidence Locker capsule inputs not frozen. <br><br> Document artefact/deliverable for ORCH-OBS-53-001 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-OBS-53-001 (status → DOING) after confirming no existing DOING/DONE owners. | Planning |
| P13 | PREP-ORCH-OBS-54-001-DEPENDS-ON-53-001 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Provenance Guild | Orchestrator Service Guild · Provenance Guild | Depends on 53-001. <br><br> Document artefact/deliverable for ORCH-OBS-54-001 and publish location so downstream tasks can proceed. |
| P13 | PREP-ORCH-OBS-54-001-DEPENDS-ON-53-001 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · Provenance Guild | Orchestrator Service Guild · Provenance Guild | Depends on 53-001. <br><br> Document artefact/deliverable for ORCH-OBS-54-001 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-OBS-54-001 (status → DOING) after confirming no existing DOING/DONE owners. | Planning |
| P14 | PREP-ORCH-OBS-55-001-DEPENDS-ON-54-001-INCIDE | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · DevOps Guild | Orchestrator Service Guild · DevOps Guild | Depends on 54-001; incident contract absent. <br><br> Document artefact/deliverable for ORCH-OBS-55-001 and publish location so downstream tasks can proceed. |
| P14 | PREP-ORCH-OBS-55-001-DEPENDS-ON-54-001-INCIDE | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild · DevOps Guild | Orchestrator Service Guild · DevOps Guild | Depends on 54-001; incident contract absent. <br><br> Document artefact/deliverable for ORCH-OBS-55-001 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-OBS-55-001 (status → DOING) after confirming no existing DOING/DONE owners. | Planning |
| P15 | PREP-ORCH-SVC-32-001-UPSTREAM-READINESS-AIRGA | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Upstream readiness (AirGap/Scanner/Graph) not confirmed; postpone bootstrap. <br><br> Document artefact/deliverable for ORCH-SVC-32-001 and publish location so downstream tasks can proceed. |
| P15 | PREP-ORCH-SVC-32-001-UPSTREAM-READINESS-AIRGA | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Upstream readiness (AirGap/Scanner/Graph) not confirmed; postpone bootstrap. <br><br> Document artefact/deliverable for ORCH-SVC-32-001 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-SVC-32-001 (status → DOING) after confirming no existing DOING/DONE owners. | Planning |
| 1 | ORCH-AIRGAP-56-001 | BLOCKED (2025-11-19) | PREP-ORCH-AIRGAP-56-001-AWAIT-SPRINT-0120-A-A | Orchestrator Service Guild · AirGap Policy Guild | Enforce job descriptors to declare network intents; flag/reject external endpoints in sealed mode. |
| 2 | ORCH-AIRGAP-56-002 | BLOCKED (2025-11-19) | PREP-ORCH-AIRGAP-56-002-UPSTREAM-56-001-BLOCK | Orchestrator Service Guild · AirGap Controller Guild | Surface sealing status and staleness in scheduling decisions; block runs when budgets exceeded. |
@@ -66,6 +66,7 @@
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-18 | Normalised sprint doc to standard template; renamed from `SPRINT_151_orchestrator_i.md`. | Planning |
| 2025-11-19 | Set all tasks to BLOCKED pending upstream readiness (AirGap/Scanner/Graph), Telemetry Core availability, and Orchestrator event schema; no executable work until contracts land. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Start of work gated on AirGap/Scanner/Graph dependencies staying green; reassess before moving tasks to DOING.

View File

@@ -19,11 +19,11 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-ORCH-SVC-41-101-DEPENDS-ON-38-101-ENVELO | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Depends on 38-101 envelope + DAL; cannot register pack-run without API/storage schema. <br><br> Document artefact/deliverable for ORCH-SVC-41-101 and publish location so downstream tasks can proceed. |
| P1 | PREP-ORCH-SVC-41-101-DEPENDS-ON-38-101-ENVELO | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Depends on 38-101 envelope + DAL; cannot register pack-run without API/storage schema. <br><br> Document artefact/deliverable for ORCH-SVC-41-101 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-SVC-41-101 (status → DOING) after confirming no existing DOING/DONE owners. | Planning |
| P2 | PREP-ORCH-SVC-42-101-DEPENDS-ON-41-101-PACK-R | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Depends on 41-101 pack-run plumbing and streaming contract. <br><br> Document artefact/deliverable for ORCH-SVC-42-101 and publish location so downstream tasks can proceed. |
| P2 | PREP-ORCH-SVC-42-101-DEPENDS-ON-41-101-PACK-R | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | Depends on 41-101 pack-run plumbing and streaming contract. <br><br> Document artefact/deliverable for ORCH-SVC-42-101 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-SVC-42-101 (status → DOING) after confirming no existing DOING/DONE owners. | Planning |
| P3 | PREP-ORCH-TEN-48-001-WEBSERVICE-LACKS-JOB-DAL | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | WebService lacks job DAL/routes; need tenant context plumbing before enforcement. <br><br> Document artefact/deliverable for ORCH-TEN-48-001 and publish location so downstream tasks can proceed. |
| P3 | PREP-ORCH-TEN-48-001-WEBSERVICE-LACKS-JOB-DAL | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Orchestrator Service Guild | Orchestrator Service Guild | WebService lacks job DAL/routes; need tenant context plumbing before enforcement. <br><br> Document artefact/deliverable for ORCH-TEN-48-001 and publish location so downstream tasks can proceed. |
| 2025-11-20 | Started PREP-ORCH-TEN-48-001 (status → DOING) after confirming no existing DOING/DONE owners. | Planning |
| 1 | ORCH-SVC-38-101 | BLOCKED | Waiting on ORCH-SVC-37-101 envelope field/semantics approval; webservice DAL still missing. | Orchestrator Service Guild | Standardize event envelope (policy/export/job lifecycle) with idempotency keys, ensure export/job failure events published to notifier bus with provenance metadata. |
| 2 | ORCH-SVC-41-101 | BLOCKED | PREP-ORCH-SVC-41-101-DEPENDS-ON-38-101-ENVELO | Orchestrator Service Guild | Register `pack-run` job type, persist run metadata, integrate logs/artifacts collection, and expose API for Task Runner scheduling. |
@@ -61,6 +61,7 @@
| 2025-11-19 | Clarified ORCH-SVC-38-101 remains BLOCKED until ORCH-SVC-37-101 envelope semantics are approved; webservice DAL still missing. | Implementer |
| 2025-11-18 | ORCH-TEN-48-001 blocked: orchestrator WebService is still template-only (no job DAL/routes), cannot enforce tenant context until real endpoints and DB session context exist. | Worker SDK Guild |
| 2025-11-19 | Set ORCH-SVC-38/41/42 and ORCH-TEN-48-001 to BLOCKED; awaiting ORCH-SVC-37-101 envelope approval and WebService DAL/schema. | Orchestrator Service Guild |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks

View File

@@ -19,8 +19,8 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-SCHED-SURFACE-01-NEED-SURFACE-FS-POINTER | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Scheduler Worker Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Scheduler Worker Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Need Surface.FS pointer model/contract; awaiting design input before planning deltas. <br><br> Document artefact/deliverable for SCHED-SURFACE-01 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/scheduler/prep/2025-11-20-surface-fs-pointer.md`. |
| P2 | PREP-SCHED-WORKER-23-101-WAITING-ON-POLICY-GU | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Scheduler Worker Guild, Policy Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Scheduler Worker Guild, Policy Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Waiting on Policy guild to supply activation event contract and throttle source. <br><br> Document artefact/deliverable for SCHED-WORKER-23-101 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/scheduler/prep/2025-11-20-worker-23-101-prep.md`. |
| P1 | PREP-SCHED-SURFACE-01-NEED-SURFACE-FS-POINTER | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Scheduler Worker Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Scheduler Worker Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Need Surface.FS pointer model/contract; awaiting design input before planning deltas. <br><br> Document artefact/deliverable for SCHED-SURFACE-01 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/scheduler/prep/2025-11-20-surface-fs-pointer.md`. |
| P2 | PREP-SCHED-WORKER-23-101-WAITING-ON-POLICY-GU | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Scheduler Worker Guild, Policy Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Scheduler Worker Guild, Policy Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Waiting on Policy guild to supply activation event contract and throttle source. <br><br> Document artefact/deliverable for SCHED-WORKER-23-101 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/scheduler/prep/2025-11-20-worker-23-101-prep.md`. |
| 0 | AGENTS-SCHEDULER-UPDATE | DONE | `src/Scheduler/AGENTS.md` created and published. | Project Manager · Architecture Guild | Populate module AGENTS charter covering roles, docs, determinism/testing rules, and allowed shared libs. |
| 1 | SCHED-IMPACT-16-303 | DONE | Implemented removal + snapshot/restore with compaction; snapshot payloads ready for RocksDB/Redis persistence. | Scheduler ImpactIndex Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex) | Snapshot/compaction + invalidation for removed images; persistence to RocksDB/Redis per architecture. |
| 2 | SCHED-SURFACE-01 | BLOCKED | PREP-SCHED-SURFACE-01-NEED-SURFACE-FS-POINTER | Scheduler Worker Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Evaluate Surface.FS pointers when planning delta scans to avoid redundant work and prioritise drift-triggered assets. |
@@ -56,6 +56,7 @@
| 2025-11-05 | Resumed instrumentation work to match `policy_simulation_latency_seconds` naming, add coverage for SSE latency recording, and validate webhook sample alignment. | Observability Guild |
| 2025-11-05 | `dotnet test` blocked by pre-existing GraphJobs accessibility errors (`IGraphJobStore.UpdateAsync`). | Scheduler Worker Guild |
| 2025-11-04 | Graph job completions now persist to Mongo with optimistic guards, emit Redis/webhook notifications once per transition, and refresh result URI metadata idempotently (tests cover service + Mongo store paths). | Scheduler Worker Guild |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Module-level AGENTS charter now present at `src/Scheduler/AGENTS.md`.

View File

@@ -19,7 +19,7 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-SCHED-WORKER-CONSOLE-23-201-BLOCKED-BY-U | BLOCKED | Due 2025-11-23 · Accountable: Scheduler Worker Guild, Observability Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Scheduler Worker Guild, Observability Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Blocked by upstream stream schema design; depends on prior resolver/eval pipeline readiness. <br><br> Document artefact/deliverable for SCHED-WORKER-CONSOLE-23-201 and publish location so downstream tasks can proceed. |
| P1 | PREP-SCHED-WORKER-CONSOLE-23-201-BLOCKED-BY-U | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Scheduler Worker Guild, Observability Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Scheduler Worker Guild, Observability Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Blocked by upstream stream schema design; depends on prior resolver/eval pipeline readiness. <br><br> Document artefact/deliverable for SCHED-WORKER-CONSOLE-23-201 and publish location so downstream tasks can proceed. |
| 0 | AGENTS-SCHEDULER-UPDATE | DONE | `src/Scheduler/AGENTS.md` created and published. | Project Manager · Architecture Guild | Create working-directory charter defining roles, prerequisites, determinism/testing rules, and allowed shared libs. |
| 1 | SCHED-WORKER-26-202 | BLOCKED | Blocked by SCHED-WORKER-26-201 (reachability joiner not delivered yet). | Scheduler Worker Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Implement staleness monitor + notifier for outdated reachability facts, publishing warnings and updating dashboards. |
| 2 | SCHED-WORKER-27-301 | BLOCKED | Blocked by SCHED-WORKER-26-202. | Scheduler Worker Guild, Policy Registry Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | Implement policy batch simulation worker: shard SBOM inventories, invoke Policy Engine, emit partial results, handle retries/backoff, and publish progress events. |
@@ -40,6 +40,7 @@
| 2025-11-17 | Normalised sprint, renamed to `SPRINT_0156_0001_0002_scheduler_ii`, and marked tasks BLOCKED pending `src/Scheduler/AGENTS.md`. | Scheduler Worker Guild |
| 2025-11-17 | Created `src/Scheduler/AGENTS.md`; unblocked tasks and reset to TODO respecting dependencies. | Scheduler Worker Guild |
| 2025-11-18 | Marked all tasks BLOCKED awaiting upstream reachability worker (SCHED-WORKER-26-201) and subsequent contract handoffs (Policy activation events, stream schema). | Scheduler Worker Guild |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Module-level AGENTS charter now present at `src/Scheduler/AGENTS.md`.

View File

@@ -22,7 +22,7 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-DVOFF-64-002-NEEDS-SEALED-BUNDLE-SPEC-SA | DONE (2025-11-20) | Due 2025-11-23 · Accountable: DevPortal Offline Guild · AirGap Controller Guild | DevPortal Offline Guild · AirGap Controller Guild | Prep artefact published at `docs/modules/export-center/prep/2025-11-20-dvoff-64-002-prep.md` (sample sealed bundle + CLI verify contract/output/exit-codes). |
| P2 | PREP-EXPORT-AIRGAP-56-001-EVIDENCELOCKER-CONT | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service Guild · Mirror Creator Guild | Exporter Service Guild · Mirror Creator Guild | EvidenceLocker contract + advisory schema to finalize DSSE contents. <br><br> Document artefact/deliverable for EXPORT-AIRGAP-56-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-export-airgap-56-001-prep.md`. |
| P2 | PREP-EXPORT-AIRGAP-56-001-EVIDENCELOCKER-CONT | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Exporter Service Guild · Mirror Creator Guild | Exporter Service Guild · Mirror Creator Guild | EvidenceLocker contract + advisory schema to finalize DSSE contents. <br><br> Document artefact/deliverable for EXPORT-AIRGAP-56-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-export-airgap-56-001-prep.md`. |
| P3 | PREP-EXPORT-AIRGAP-56-002-DEPENDS-ON-56-001-S | DONE (2025-11-20) | Prep artefact at `docs/modules/export-center/prep/2025-11-20-export-airgap-56-002-prep.md`; waiting on 56-001 schema to unblock impl. | Exporter Service Guild · DevOps Guild | Depends on 56-001; same schema prerequisites. <br><br> Document artefact/deliverable for EXPORT-AIRGAP-56-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-export-airgap-56-002-prep.md`. |
| P4 | PREP-EXPORT-AIRGAP-57-001-DEPENDS-ON-56-002-N | DONE (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service Guild · Evidence Locker Guild | Exporter Service Guild · Evidence Locker Guild | Depends on 56-002; needs sealed evidence bundle format. <br><br> Prep artefact published at `docs/modules/export-center/prep/2025-11-20-export-airgap-57-001-prep.md` (export portable bundle contract, deterministic packaging, API surface, acceptance criteria). |
| P5 | PREP-EXPORT-AIRGAP-58-001-DEPENDS-ON-57-001-N | DONE (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service Guild · Notifications Guild | Exporter Service Guild · Notifications Guild | Depends on 57-001; prep artefact published at `docs/modules/export-center/prep/2025-11-20-export-airgap-58-001-prep.md` detailing notification payload, retries, deterministic headers, and linkage to export download. |
@@ -109,3 +109,4 @@
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-12 | Snapshot captured (pre-template) with tasks TODO. | Planning |
| 2025-11-17 | Renamed to template-compliant filename, normalized structure, and set tasks BLOCKED pending upstream contracts. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |

View File

@@ -20,16 +20,16 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-EXPORT-OBS-50-001-WAIT-FOR-EXPORTER-SERV | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service · Observability Guild | Exporter Service · Observability Guild | Wait for exporter service bootstrap + telemetry schema. <br><br> Document artefact/deliverable for EXPORT-OBS-50-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-obs-50-001-prep.md`. |
| P2 | PREP-EXPORT-RISK-69-001-AWAIT-PHASE-I-ARTIFAC | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service · Risk Bundle Export Guild | Exporter Service · Risk Bundle Export Guild | Await phase I artifacts + schema; needs provider selection rules. <br><br> Document artefact/deliverable for EXPORT-RISK-69-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-risk-69-001-prep.md`. |
| P3 | PREP-EXPORT-SVC-35-001-NEEDS-PHASE-I-READINES | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Needs phase I readiness + synthetic telemetry feeds. <br><br> Document artefact/deliverable for EXPORT-SVC-35-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-001-prep.md`. |
| P4 | PREP-EXPORT-SVC-35-002-DEPENDS-ON-35-001 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Depends on 35-001. <br><br> Document artefact/deliverable for EXPORT-SVC-35-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-002-prep.md`. |
| P5 | PREP-EXPORT-SVC-35-003-DEPENDS-ON-35-002 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Depends on 35-002. <br><br> Document artefact/deliverable for EXPORT-SVC-35-003 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-003-prep.md`. |
| P6 | PREP-EXPORT-SVC-35-004-DEPENDS-ON-35-003 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Depends on 35-003. <br><br> Document artefact/deliverable for EXPORT-SVC-35-004 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-004-prep.md`. |
| P7 | PREP-EXPORT-SVC-35-005-DEPENDS-ON-35-004 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Depends on 35-004. <br><br> Document artefact/deliverable for EXPORT-SVC-35-005 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-005-prep.md`. |
| P8 | PREP-EXPORT-NOTIFY-SCHEMA-OBS-52 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Notifications Guild · Exporter Service | Notifications Guild · Exporter Service | Notifications schema for export lifecycle events not published; required for EXPORT-OBS-52-001 and downstream tasks. Provide envelope + sample payloads. Prep artefact: `docs/modules/export-center/prep/2025-11-20-notify-obs-52-prep.md`. |
| P8 | PREP-EXPORT-CRYPTO-90-001-PENDING-NOV-18-CRYP | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Exporter Service · Security Guild | Exporter Service · Security Guild | Pending Nov-18 crypto review + reference implementation. <br><br> Document artefact/deliverable for EXPORT-CRYPTO-90-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-crypto-90-001-prep.md`. |
| P9 | PREP-EXPORTER-SERVICE-BLOCKED-WAITING-ON-EVID | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Planning | Planning | BLOCKED (waiting on EvidenceLocker spec). <br><br> Document artefact/deliverable for Exporter Service and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-exporter-evid-blocker.md`. |
| P1 | PREP-EXPORT-OBS-50-001-WAIT-FOR-EXPORTER-SERV | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Exporter Service · Observability Guild | Exporter Service · Observability Guild | Wait for exporter service bootstrap + telemetry schema. <br><br> Document artefact/deliverable for EXPORT-OBS-50-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-obs-50-001-prep.md`. |
| P2 | PREP-EXPORT-RISK-69-001-AWAIT-PHASE-I-ARTIFAC | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Exporter Service · Risk Bundle Export Guild | Exporter Service · Risk Bundle Export Guild | Await phase I artifacts + schema; needs provider selection rules. <br><br> Document artefact/deliverable for EXPORT-RISK-69-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-risk-69-001-prep.md`. |
| P3 | PREP-EXPORT-SVC-35-001-NEEDS-PHASE-I-READINES | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Needs phase I readiness + synthetic telemetry feeds. <br><br> Document artefact/deliverable for EXPORT-SVC-35-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-001-prep.md`. |
| P4 | PREP-EXPORT-SVC-35-002-DEPENDS-ON-35-001 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Depends on 35-001. <br><br> Document artefact/deliverable for EXPORT-SVC-35-002 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-002-prep.md`. |
| P5 | PREP-EXPORT-SVC-35-003-DEPENDS-ON-35-002 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Depends on 35-002. <br><br> Document artefact/deliverable for EXPORT-SVC-35-003 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-003-prep.md`. |
| P6 | PREP-EXPORT-SVC-35-004-DEPENDS-ON-35-003 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Depends on 35-003. <br><br> Document artefact/deliverable for EXPORT-SVC-35-004 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-004-prep.md`. |
| P7 | PREP-EXPORT-SVC-35-005-DEPENDS-ON-35-004 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Exporter Service | Exporter Service | Depends on 35-004. <br><br> Document artefact/deliverable for EXPORT-SVC-35-005 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-svc-35-005-prep.md`. |
| P8 | PREP-EXPORT-NOTIFY-SCHEMA-OBS-52 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Notifications Guild · Exporter Service | Notifications Guild · Exporter Service | Notifications schema for export lifecycle events not published; required for EXPORT-OBS-52-001 and downstream tasks. Provide envelope + sample payloads. Prep artefact: `docs/modules/export-center/prep/2025-11-20-notify-obs-52-prep.md`. |
| P8 | PREP-EXPORT-CRYPTO-90-001-PENDING-NOV-18-CRYP | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Exporter Service · Security Guild | Exporter Service · Security Guild | Pending Nov-18 crypto review + reference implementation. <br><br> Document artefact/deliverable for EXPORT-CRYPTO-90-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-crypto-90-001-prep.md`. |
| P9 | PREP-EXPORTER-SERVICE-BLOCKED-WAITING-ON-EVID | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Planning | Planning | BLOCKED (waiting on EvidenceLocker spec). <br><br> Document artefact/deliverable for Exporter Service and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/export-center/prep/2025-11-20-exporter-evid-blocker.md`. |
| 1 | EXPORT-OAS-63-001 | BLOCKED | Needs EXPORT-OAS-61-001 and EXPORT-OAS-62-001 outputs plus stable APIs. | Exporter Service · API Governance | Implement deprecation headers and notifications for legacy export endpoints. |
| 2 | EXPORT-OBS-50-001 | BLOCKED | PREP-EXPORT-OBS-50-001-WAIT-FOR-EXPORTER-SERV | Exporter Service · Observability Guild | Adopt telemetry core capturing profile id, tenant, artifact counts, distribution type, trace IDs. |
| 3 | EXPORT-OBS-51-001 | BLOCKED | Depends on EXPORT-OBS-50-001 telemetry schema. | Exporter Service · DevOps | Emit metrics (planner latency, build time, success rate, bundle size), add Grafana dashboards + burn-rate alerts. |
@@ -96,3 +96,4 @@
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-12 | Snapshot captured (pre-template) with tasks TODO. | Planning |
| 2025-11-17 | Renamed to compliant filename, applied template, and set tasks to BLOCKED pending upstream contracts and Sprint 0162 outputs. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |

View File

@@ -19,7 +19,7 @@
## Delivery Tracker
| # | Track | Status | Key dependency / next step | Owners | Notes |
| --- | --- | --- | --- | --- | --- |
| 1 | 170.A · Notifier readiness | BLOCKED (2025-11-19) | Await CI restore for NOTIFY-OBS-51-001 SLO webhook tests; risk routing still depends on POLICY-RISK-40-002 export. | Notifications Service Guild · Attestor Service Guild · Observability Guild | Active work mirrored to Sprint 0171; attestation/OAS tracks are done, observability/risk tracks paused until dependencies clear. |
| 1 | 170.A · Notifier readiness | DONE (2025-11-22) | SLO webhook tests passed; incident-mode templates shipped. Risk routing still pending POLICY-RISK-40-002 but scoped to later track. | Notifications Service Guild · Attestor Service Guild · Observability Guild | NOTIFY-OBS-51-001 validated; NOTIFY-OBS-55-001 templates/rules published. Remaining risk alerts tracked in Sprint 0171 tasks 911. |
| 2 | 170.B · Telemetry bootstrap | BLOCKED (2025-11-19) | TELEMETRY-OBS-50-001 shipped; propagation adapters (50-002) waiting on bootstrap adoption + CLI toggle contract (CLI-OBS-12-001). | Telemetry Core Guild · Observability Guild · Security Guild | Bootstrap of `StellaOps.Telemetry.Core` complete; downstream propagation/scrub/incident work paused until contracts/tests land (see Sprint 0174). |
## Execution Log
@@ -31,6 +31,7 @@
| 2025-11-19 | Re-baselined tracks: set 170.A and 170.B to BLOCKED pending CI restore (Notifier SLO tests) and propagation/toggle contracts; TELEMETRY-OBS-50-001 marked DONE in Sprint 0174. | Implementer |
| 2025-11-12 | Documented attestation template suite in `docs/notifications/templates.md` to unblock NOTIFY-ATTEST-74-001; synced notifications docs. | Notifications Service Guild |
| 2025-11-19 | Normalized sprint to standard template and renamed from `SPRINT_170_notifications_telemetry.md` to `SPRINT_0170_0001_0001_notifications_telemetry.md`; content preserved; legacy stub added. | Implementer |
| 2025-11-22 | Marked 170.A DONE after NOTIFY-OBS-51-001 tests passed and incident-mode templates/rules landed (NOTIFY-OBS-55-001). Risk alerts remain pending POLICY-RISK-40-002 and stay tracked under Sprint 0171 tasks 911. | Implementer |
## Decisions & Risks
- Orchestrator observability contracts (ORCH-OBS-50-001) must land before enabling Notifier SLO webhooks and Telemetry helpers.

View File

@@ -27,11 +27,11 @@
| 4 | NOTIFY-OAS-61-002 | DONE (2025-11-17) | Depends on 61-001. | Notifications Service Guild | Implement `/.well-known/openapi` discovery endpoint with scope metadata. |
| 5 | NOTIFY-OAS-62-001 | DONE (2025-11-17) | Depends on 61-002. | Notifications Service Guild · SDK Generator Guild | SDK examples for rule CRUD, incident ack, quiet hours; SDK smoke tests. |
| 6 | NOTIFY-OAS-63-001 | DONE (2025-11-17) | Depends on 62-001. | Notifications Service Guild · API Governance Guild | Emit deprecation headers and templates for retiring notifier APIs. |
| 7 | NOTIFY-OBS-51-001 | BLOCKED (2025-11-19) | CI restore for `HttpEgressSloSinkTests` / `EventProcessorTests` | Notifications Service Guild · Observability Guild | Integrate SLO evaluator webhooks into Notifier rules; templates/routing/suppression; sample policies. |
| 8 | NOTIFY-OBS-55-001 | TODO | Depends on 51-001. | Notifications Service Guild · Ops Guild | Publish incident mode start/stop notifications with trace/evidence links, retention notes, quiet-hour overrides, legal logging. |
| 9 | NOTIFY-RISK-66-001 | TODO | Depends on POLICY-RISK-40-002 metadata export. | Notifications Service Guild · Risk Engine Guild | Add notification triggers for risk severity escalation/downgrade with profile metadata. |
| 10 | NOTIFY-RISK-67-001 | TODO | Depends on 66-001. | Notifications Service Guild · Policy Guild | Notify when risk profiles are published/deprecated/thresholds change. |
| 11 | NOTIFY-RISK-68-001 | TODO | Depends on 67-001. | Notifications Service Guild | Per-profile routing, quiet hours, dedupe for risk alerts; integrate CLI/Console preferences. |
| 7 | NOTIFY-OBS-51-001 | DONE (2025-11-22) | Filtered `HttpEgressSloSinkTests` / `EventProcessorTests` now passing; TRX at `src/Notifier/StellaOps.Notifier/StellaOps.Notifier.Tests/TestResults/notifier-slo-tests.trx`. | Notifications Service Guild · Observability Guild | Integrate SLO evaluator webhooks into Notifier rules; templates/routing/suppression; sample policies. |
| 8 | NOTIFY-OBS-55-001 | DONE (2025-11-22) | Depends on 51-001. | Notifications Service Guild · Ops Guild | Incident mode start/stop templates and importable rules published with evidence/trace links, retention notes, quiet-hour overrides, and legal logging metadata. |
| 9 | NOTIFY-RISK-66-001 | BLOCKED (2025-11-22) | Depends on POLICY-RISK-40-002 metadata export. | Notifications Service Guild · Risk Engine Guild | Add notification triggers for risk severity escalation/downgrade with profile metadata. |
| 10 | NOTIFY-RISK-67-001 | BLOCKED (2025-11-22) | Depends on 66-001. | Notifications Service Guild · Policy Guild | Notify when risk profiles are published/deprecated/thresholds change. |
| 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. |
@@ -55,6 +55,10 @@
| 2025-11-19 | Marked NOTIFY-OBS-51-001 status to DOING; OBS SLO webhook code ready, pending CI validation to close the task. | Implementer |
| 2025-11-19 | Action item: run CI pipeline for Notifier with filters `HttpEgressSloSinkTests` and `EventProcessorTests`; if green, set NOTIFY-OBS-51-001 to DONE and attach TRX artefacts. | Implementer |
| 2025-11-19 | Set NOTIFY-OBS-51-001 to BLOCKED pending CI restore capacity; local restore repeatedly cancels (NuGet.targets:196). No further code changes until CI evidence available. | Implementer |
| 2025-11-22 | Resumed NOTIFY-OBS-51-001 after restore fixes; running filtered tests locally with TRX capture to validate SLO webhook sink and processor. | Implementer |
| 2025-11-22 | `HttpEgressSloSinkTests` and `EventProcessorTests` passed locally after wiring PackApprovals collection options + Mongo cursor fix; TRX evidence recorded at `src/Notifier/StellaOps.Notifier/StellaOps.Notifier.Tests/TestResults/notifier-slo-tests.trx`. | Implementer |
| 2025-11-22 | Authored incident-mode templates + sample rules (`tmpl-incident-start/stop`) with evidence/trace/retention/legal context and quiet-hour overrides; published bundle at `src/Notifier/StellaOps.Notifier/docs/incident-mode-rules.sample.json` and updated `docs/notifications/templates.md`. Marked NOTIFY-OBS-55-001 DONE. | Implementer |
| 2025-11-22 | Marked NOTIFY-RISK-66-001/67-001/68-001 BLOCKED pending POLICY-RISK-40-002 export; no implementation started. | Implementer |
| 2025-11-19 | Added QA playbook for NOTIFY-ATTEST-74-002 (`src/Notifier/StellaOps.Notifier/StellaOps.Notifier.docs/QA-attestation-routing.md`) detailing import steps, event kinds, expected deliveries, and evidence to capture. | Implementer |
| 2025-11-20 | No unblocked work left in this sprint today: NOTIFY-ATTEST-74-002 depends on attestor payload localization freeze; NOTIFY-OBS-51/55 blocked until SLO webhook contract is wired into worker; NOTIFY-RISK-66..68 waits on `POLICY-RISK-40-002` export. Moving to next sprint. | Implementer |

View File

@@ -18,7 +18,7 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-NOTIFY-TEN-48-001-NOTIFIER-II-SPRINT-017 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Notifications Service Guild (`src/Notifier/StellaOps.Notifier`) | Notifications Service Guild (`src/Notifier/StellaOps.Notifier`) | Notifier II (Sprint 0172) not started; tenancy model not finalized. <br><br> Document artefact/deliverable for NOTIFY-TEN-48-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/notifier/prep/2025-11-20-ten-48-001-prep.md`. |
| P1 | PREP-NOTIFY-TEN-48-001-NOTIFIER-II-SPRINT-017 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Notifications Service Guild (`src/Notifier/StellaOps.Notifier`) | Notifications Service Guild (`src/Notifier/StellaOps.Notifier`) | Notifier II (Sprint 0172) not started; tenancy model not finalized. <br><br> Document artefact/deliverable for NOTIFY-TEN-48-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/notifier/prep/2025-11-20-ten-48-001-prep.md`. |
| 1 | NOTIFY-TEN-48-001 | BLOCKED (2025-11-20) | PREP-NOTIFY-TEN-48-001-NOTIFIER-II-SPRINT-017 | Notifications Service Guild (`src/Notifier/StellaOps.Notifier`) | Tenant-scope rules/templates/incidents, RLS on storage, tenant-prefixed channels, include tenant context in notifications. |
## Execution Log
@@ -29,6 +29,7 @@
| 2025-11-19 | Normalized sprint to standard template and renamed from `SPRINT_173_notifier_iii.md` to `SPRINT_0173_0001_0003_notifier_iii.md`; content preserved. | Implementer |
| 2025-11-19 | Added legacy-file redirect stub to avoid divergent updates. | Implementer |
| 2025-11-20 | Marked NOTIFY-TEN-48-001 BLOCKED pending completion of Sprint 0172 tenancy model; no executable work in this sprint today. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Requires completion of Notifier II and established tenancy model before applying RLS.

View File

@@ -43,9 +43,10 @@
| 2025-11-19 | Normalized sprint to standard template and renamed from `SPRINT_174_telemetry.md` to `SPRINT_0174_0001_0001_telemetry.md`; content preserved. | Implementer |
| 2025-11-19 | Added legacy-file redirect stub to avoid divergent updates. | Implementer |
| 2025-11-20 | Marked tasks 50-002..56-001 BLOCKED: waiting on 50-001 package publication, Security scrub policy, and CLI incident-toggle contract; no executable work until upstream artefacts land. | Implementer |
| 2025-11-19 | PREP-TELEMETRY-OBS-50-002-AWAIT-PUBLISHED-50 completed; bootstrap doc published. Downstream tasks remain blocked on propagation/scrub/toggle contracts. | Implementer |
| 2025-11-19 | PREP-TELEMETRY-OBS-50-002-AWAIT-PUBLISHED-50 completed; bootstrap doc published. Downstream tasks remain blocked on propagation/scrub/toggle contracts. | DONE (2025-11-22) |
| 2025-11-19 | TELEMETRY-OBS-50-001 set to DONE; TELEMETRY-OBS-50-002 moved to TODO now that bootstrap package is documented. | Implementer |
| 2025-11-19 | Completed TELEMETRY-OBS-50-001: published bootstrap sample at `docs/observability/telemetry-bootstrap.md`; library already present. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Propagation adapters wait on bootstrap package; Security scrub policy (POLICY-SEC-42-003) must approve before implementing 51-001/51-002.

View File

@@ -20,10 +20,10 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-EVID-REPLAY-187-001-SCANNER-RECORD-PAYLO | DONE (2025-11-20) | Due 2025-11-23 · Accountable: Evidence Locker Guild (`src/EvidenceLocker/StellaOps.EvidenceLocker`, docs) | Evidence Locker Guild (`src/EvidenceLocker/StellaOps.EvidenceLocker`, docs) | Prep artefact published at `docs/modules/evidence-locker/replay-payload-contract.md` (scanner record payload shape, determinism, sample expectations). |
| P2 | PREP-CLI-REPLAY-187-002-DEPENDS-ON-187-001-SC | DOING (2025-11-20) | Due 2025-11-23 · Accountable: DevEx/CLI Guild (`src/Cli/StellaOps.Cli`, docs) | DevEx/CLI Guild (`src/Cli/StellaOps.Cli`, docs) | Depends on 187-001 schema freeze. <br><br> Document artefact/deliverable for CLI-REPLAY-187-002 and publish location so downstream tasks can proceed. |
| P3 | PREP-ATTEST-REPLAY-187-003-DEPENDS-ON-187-001 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Attestor Guild (`src/Attestor/StellaOps.Attestor`, docs) | Attestor Guild (`src/Attestor/StellaOps.Attestor`, docs) | Depends on 187-001 payloads. <br><br> Document artefact/deliverable for ATTEST-REPLAY-187-003 and publish location so downstream tasks can proceed. |
| P4 | PREP-RUNBOOK-REPLAY-187-004-NEEDS-APIS-DEFINE | DOING (2025-11-20) | Due 2025-11-23 · Accountable: Docs Guild · Ops Guild (docs/runbooks) | Docs Guild · Ops Guild (docs/runbooks) | Needs APIs defined from 187-001. <br><br> Document artefact/deliverable for RUNBOOK-REPLAY-187-004 and publish location so downstream tasks can proceed. |
| P5 | PREP-VALIDATE-BUNDLE-187-005-DEPENDS-ON-187-0 | DOING (2025-11-20) | Due 2025-11-23 · Accountable: QA Guild · CLI Guild · Docs Guild | QA Guild · CLI Guild · Docs Guild | Depends on 187-001/002/003; no payloads yet. <br><br> Document artefact/deliverable for VALIDATE-BUNDLE-187-005 and publish location so downstream tasks can proceed. |
| P2 | PREP-CLI-REPLAY-187-002-DEPENDS-ON-187-001-SC | DONE (2025-11-22) | Due 2025-11-23 · Accountable: DevEx/CLI Guild (`src/Cli/StellaOps.Cli`, docs) | DevEx/CLI Guild (`src/Cli/StellaOps.Cli`, docs) | Depends on 187-001 schema freeze. <br><br> Document artefact/deliverable for CLI-REPLAY-187-002 and publish location so downstream tasks can proceed. |
| P3 | PREP-ATTEST-REPLAY-187-003-DEPENDS-ON-187-001 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Attestor Guild (`src/Attestor/StellaOps.Attestor`, docs) | Attestor Guild (`src/Attestor/StellaOps.Attestor`, docs) | Depends on 187-001 payloads. <br><br> Document artefact/deliverable for ATTEST-REPLAY-187-003 and publish location so downstream tasks can proceed. |
| P4 | PREP-RUNBOOK-REPLAY-187-004-NEEDS-APIS-DEFINE | DONE (2025-11-22) | Due 2025-11-23 · Accountable: Docs Guild · Ops Guild (docs/runbooks) | Docs Guild · Ops Guild (docs/runbooks) | Needs APIs defined from 187-001. <br><br> Document artefact/deliverable for RUNBOOK-REPLAY-187-004 and publish location so downstream tasks can proceed. |
| P5 | PREP-VALIDATE-BUNDLE-187-005-DEPENDS-ON-187-0 | DONE (2025-11-22) | Due 2025-11-23 · Accountable: QA Guild · CLI Guild · Docs Guild | QA Guild · CLI Guild · Docs Guild | Depends on 187-001/002/003; no payloads yet. <br><br> Document artefact/deliverable for VALIDATE-BUNDLE-187-005 and publish location so downstream tasks can proceed. |
| P6 | PREP-EVID-CRYPTO-90-001-ICRYPTOPROVIDERREGIST | DONE (2025-11-20) | Due 2025-11-23 · Accountable: Evidence Locker Guild · Security Guild (`src/EvidenceLocker/StellaOps.EvidenceLocker`) | Evidence Locker Guild · Security Guild (`src/EvidenceLocker/StellaOps.EvidenceLocker`) | Prep artefact published at `docs/modules/evidence-locker/crypto-provider-registry-prep.md` (provider registry expectations, config, JWKS caching). |
| 1 | EVID-REPLAY-187-001 | BLOCKED (2025-11-20) | PREP-EVID-REPLAY-187-001-SCANNER-RECORD-PAYLO | Evidence Locker Guild (`src/EvidenceLocker/StellaOps.EvidenceLocker`, docs) | Implement replay bundle ingestion/retention APIs; document storage/retention rules referencing replay doc §§2 & 8. |
| 2 | CLI-REPLAY-187-002 | BLOCKED (2025-11-20) | PREP-CLI-REPLAY-187-002-DEPENDS-ON-187-001-SC | DevEx/CLI Guild (`src/Cli/StellaOps.Cli`, docs) | Add `scan --record`, `verify`, `replay`, `diff` commands with offline bundle resolution; update CLI architecture and replay appendix. |
@@ -45,6 +45,7 @@
| 2025-11-19 | Normalized sprint to standard template and renamed from `SPRINT_187_evidence_locker_cli_integration.md` to `SPRINT_0187_0001_0001_evidence_locker_cli_integration.md`; content preserved. | Implementer |
| 2025-11-19 | Added legacy-file redirect stub to avoid divergent updates. | Implementer |
| 2025-11-20 | Marked all tasks BLOCKED: waiting on Scanner record payloads (Sprint 0186) and ICryptoProviderRegistry readiness; no executable work in this sprint until upstream artefacts land. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- EvidenceLocker API schema must align with replay bundles and sovereign crypto routing; approval review on 2025-11-18.

View File

@@ -20,10 +20,10 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-GRAPH-OPS-0001-WAITING-FOR-NEXT-DEMO-OUT | DOING (2025-11-20) | Due 2025-11-25 · Accountable: Ops Guild | Ops Guild | Waiting for next demo outputs to review dashboards/runbooks. <br><br> Document artefact/deliverable for GRAPH-OPS-0001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/graph/prep/2025-11-20-ops-0001-prep.md`. |
| P1 | PREP-GRAPH-OPS-0001-WAITING-FOR-NEXT-DEMO-OUT | DONE (2025-11-22) | Due 2025-11-25 · Accountable: Ops Guild | Ops Guild | Waiting for next demo outputs to review dashboards/runbooks. <br><br> Document artefact/deliverable for GRAPH-OPS-0001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/graph/prep/2025-11-20-ops-0001-prep.md`. |
| 1 | GRAPH-ENG-0001 | DONE | Synced docs to Sprint 0141 rename on 2025-11-17 | Module Team | Keep module milestones in sync with `/docs/implplan/SPRINT_0141_0001_0001_graph_indexer.md` and related files; update references and note deltas. |
| 2 | GRAPH-DOCS-0002 | BLOCKED | Await DOCS-GRAPH-24-003 cross-links | Docs Guild | Add API/query doc cross-links once DOCS-GRAPH-24-003 lands. |
| 3 | GRAPH-OPS-0001 | BLOCKED | PREP-GRAPH-OPS-0001-WAITING-FOR-NEXT-DEMO-OUT | Ops Guild | Review graph observability dashboards/runbooks after the next sprint demo; capture updates in runbooks. |
| 3 | GRAPH-OPS-0001 | TODO | PREP-GRAPH-OPS-0001-WAITING-FOR-NEXT-DEMO-OUT | Ops Guild | Review graph observability dashboards/runbooks after the next sprint demo; capture updates in runbooks. |
## Execution Log
| Date (UTC) | Update | Owner |
@@ -33,6 +33,8 @@
| 2025-11-17 | Marked GRAPH-DOCS-0002 and GRAPH-OPS-0001 as BLOCKED pending DOCS-GRAPH-24-003 + next demo outputs. | Module Team |
| 2025-11-17 | Completed GRAPH-ENG-0001; README and implementation_plan now reference SPRINT_0141_0001_0001_graph_indexer.md. | Module Team |
| 2025-11-17 | Normalised sprint to standard template; renamed from SPRINT_321_docs_modules_graph.md. | Docs |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-11-22 | PREP-GRAPH-OPS-0001 done; moved GRAPH-OPS-0001 to TODO pending next demo outputs. | Project Mgmt |
## Decisions & Risks
- Cross-links blocked on DOCS-GRAPH-24-003; track before marking GRAPH-DOCS-0002 done.

View File

@@ -20,11 +20,11 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-SAMPLES-LNM-22-001-WAITING-ON-FINALIZED | DONE (2025-11-20) | Due 2025-11-26 · Accountable: Samples Guild · Concelier Guild | Samples Guild · Concelier Guild | Prep artefact published at `docs/samples/linkset/prep-22-001.md` (fixtures plan aligned to frozen LNM schema; deterministic seeds/checksums). |
| P2 | PREP-SAMPLES-LNM-22-002-DEPENDS-ON-22-001-OUT | DOING (2025-11-20) | Due 2025-11-26 · Accountable: Samples Guild · Excititor Guild | Samples Guild · Excititor Guild | Depends on 22-001 outputs; will build Excititor observation/VEX linkset fixtures once P1 samples land. Prep doc will extend `docs/samples/linkset/prep-22-001.md` with Excititor-specific payloads. |
| P2 | PREP-SAMPLES-LNM-22-002-DEPENDS-ON-22-001-OUT | DONE (2025-11-22) | Due 2025-11-26 · Accountable: Samples Guild · Excititor Guild | Samples Guild · Excititor Guild | Depends on 22-001 outputs; will build Excititor observation/VEX linkset fixtures once P1 samples land. Prep doc will extend `docs/samples/linkset/prep-22-001.md` with Excititor-specific payloads. |
| 1 | SAMPLES-GRAPH-24-003 | BLOCKED | Await Graph overlay format decision + mock SBOM cache availability | Samples Guild · SBOM Service Guild | Generate large-scale SBOM graph fixture (~40k nodes) with policy overlay snapshot for perf/regression suites. |
| 2 | SAMPLES-GRAPH-24-004 | TODO | Blocked on 24-003 fixture availability | Samples Guild · UI Guild | Create vulnerability explorer JSON/CSV fixtures capturing conflicting evidence and policy outputs for UI/CLI automated tests. |
| 3 | SAMPLES-LNM-22-001 | BLOCKED | PREP-SAMPLES-LNM-22-001-WAITING-ON-FINALIZED | Samples Guild · Concelier Guild | Create advisory observation/linkset fixtures (NVD, GHSA, OSV disagreements) for API/CLI/UI tests with documented conflicts. |
| 4 | SAMPLES-LNM-22-002 | BLOCKED | PREP-SAMPLES-LNM-22-002-DEPENDS-ON-22-001-OUT | Samples Guild · Excititor Guild | Produce VEX observation/linkset fixtures demonstrating status conflicts and path relevance; include raw blobs. |
| 3 | SAMPLES-LNM-22-001 | TODO | PREP-SAMPLES-LNM-22-001-WAITING-ON-FINALIZED | Samples Guild · Concelier Guild | Create advisory observation/linkset fixtures (NVD, GHSA, OSV disagreements) for API/CLI/UI tests with documented conflicts. |
| 4 | SAMPLES-LNM-22-002 | TODO | PREP-SAMPLES-LNM-22-002-DEPENDS-ON-22-001-OUT | Samples Guild · Excititor Guild | Produce VEX observation/linkset fixtures demonstrating status conflicts and path relevance; include raw blobs. |
## Execution Log
| Date (UTC) | Update | Owner |
@@ -33,10 +33,12 @@
| 2025-11-20 | Started PREP-SAMPLES-LNM-22-002 (dependent on 22-001); status set to DOING. | Planning |
| 2025-11-19 | Normalized PREP-SAMPLES-LNM-22-001 Task ID (removed trailing hyphen) for dependency tracking. | Project Mgmt |
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-22 | PREP extended for Excititor fixtures; moved SAMPLES-LNM-22-001 and SAMPLES-LNM-22-002 to TODO. | Project Mgmt |
| 2025-11-18 | Drafted fixture plan (`samples/graph/fixtures-plan.md`) outlining contents, assumptions, and blockers for SAMPLES-GRAPH-24-003. | Samples |
| 2025-11-18 | Kicked off SAMPLES-GRAPH-24-003 (overlay format + mock bundle sources); other tasks unchanged. | Samples |
| 2025-11-18 | Normalised sprint to standard template; renamed from SPRINT_509_samples.md. | Ops/Docs |
| 2025-11-19 | Marked SAMPLES-GRAPH-24-003 BLOCKED pending Graph overlay format decision and mock SBOM cache availability. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Linkset fixtures blocked by Concelier/Excititor schema finalization; revisit once schemas freeze.

View File

@@ -61,16 +61,17 @@
| 2025-11-20 | EXCITITOR-AIAI-31-003 DONE: chunk telemetry meter and metrics wiring landed in Program.cs; ops note at docs/modules/excititor/operations/chunk-telemetry.md. | Implementer |
| 2025-11-20 | Marked EXCITITOR-AIAI-31-002 DONE; chunk API OpenAPI spec added at docs/modules/excititor/schemas/vex-chunk-api.yaml. | Implementer |
| 2025-11-20 | EXCITITOR-AIAI-31-002 unblocked (prep complete); starting chunk API spec + schema under docs/modules/excititor/schemas. | Implementer |
| 2025-11-20 | PREP-MIRROR-STAFFING completed; staffing/milestones recorded at docs/modules/mirror/assembler.md. | Implementer |
| 2025-11-20 | PREP-EXCITITOR-ATTESTATION-PLAN completed; plan at docs/modules/excititor/attestation-plan.md. | Implementer |
| 2025-11-20 | PREP-FEEDCONN-ICS-KISA-PLAN completed; remediation plan lives at docs/modules/concelier/feeds/icscisa-kisa.md (v0.1). | Implementer |
| 2025-11-20 | PREP-EVIDENCE-LOCKER-CONTRACT completed; contract published at docs/modules/evidence-locker/attestation-contract.md. | Implementer |
| 2025-11-20 | PREP-LNM-SCHEMA-APPROVAL completed; schema frozen in docs/modules/concelier/link-not-merge-schema.md; samples in docs/samples/lnm/*.json. | Implementer |
| 2025-11-20 | PREP-MIRROR-STAFFING completed; staffing/milestones recorded at docs/modules/mirror/assembler.md. | DONE (2025-11-22) |
| 2025-11-20 | PREP-EXCITITOR-ATTESTATION-PLAN completed; plan at docs/modules/excititor/attestation-plan.md. | DONE (2025-11-22) |
| 2025-11-20 | PREP-FEEDCONN-ICS-KISA-PLAN completed; remediation plan lives at docs/modules/concelier/feeds/icscisa-kisa.md (v0.1). | DONE (2025-11-22) |
| 2025-11-20 | PREP-EVIDENCE-LOCKER-CONTRACT completed; contract published at docs/modules/evidence-locker/attestation-contract.md. | DONE (2025-11-22) |
| 2025-11-20 | PREP-LNM-SCHEMA-APPROVAL completed; schema frozen in docs/modules/concelier/link-not-merge-schema.md; samples in docs/samples/lnm/*.json. | DONE (2025-11-22) |
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-13 | Refreshed wave tracker, decisions, and contingency plan ahead of 1415 Nov checkpoints; outstanding asks: SBOM/CLI/Policy/DevOps ETAs, Link-Not-Merge approval, Mirror staffing. | Sprint 110 leads |
| 2025-11-09 | Captured initial wave scope, interlocks, and risks covering SBOM/CLI/Policy/DevOps artefacts, Link-Not-Merge schemas, Excititor justification backlog, and Mirror assembler commitments. | Sprint 110 leads |
| 2025-11-16 | Updated task board: marked Advisory AI packaging, Concelier air-gap/console/attestation tracks, Excititor chunk/attestation/air-gap tracks, and all Mirror tracks as BLOCKED pending schema approvals, Evidence Locker contract, and Mirror staffing decisions. | Implementer |
| 2025-11-16 | Marked CONCELIER-AIAI-31-002 BLOCKED (waiting on Link-Not-Merge schema approval); progressed DOCS-AIAI-31-004 doc draft. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
### Decisions in flight

View File

@@ -10,8 +10,8 @@ Focus: Policy & Reasoning focus on Policy (phase I).
| # | Task ID & handle | State | Key dependency / next step | Owners |
| --- | --- | --- | --- | --- |
| P1 | PREP-EXPORT-CONSOLE-23-001-MISSING-EXPORT-BUN | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Policy Guild, Scheduler Guild, Observability Guild / src/Policy/StellaOps.Policy.Engine | Policy Guild, Scheduler Guild, Observability Guild / src/Policy/StellaOps.Policy.Engine | Missing export bundle contract/API surface and scheduler job spec for Console; requires agreed schema and job wiring. <br><br> Document artefact/deliverable for EXPORT-CONSOLE-23-001 and publish location so downstream tasks can proceed. |
| P2 | PREP-POLICY-AIRGAP-56-001-MIRROR-BUNDLE-SCHEM | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Policy Guild / src/Policy/StellaOps.Policy.Engine | Policy Guild / src/Policy/StellaOps.Policy.Engine | Mirror bundle schema for policy packs not published; need bundle_id/provenance fields and sealed-mode rules. <br><br> Document artefact/deliverable for POLICY-AIRGAP-56-001 and publish location so downstream tasks can proceed. |
| P1 | PREP-EXPORT-CONSOLE-23-001-MISSING-EXPORT-BUN | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Policy Guild, Scheduler Guild, Observability Guild / src/Policy/StellaOps.Policy.Engine | Policy Guild, Scheduler Guild, Observability Guild / src/Policy/StellaOps.Policy.Engine | Missing export bundle contract/API surface and scheduler job spec for Console; requires agreed schema and job wiring. <br><br> Document artefact/deliverable for EXPORT-CONSOLE-23-001 and publish location so downstream tasks can proceed. |
| P2 | PREP-POLICY-AIRGAP-56-001-MIRROR-BUNDLE-SCHEM | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Policy Guild / src/Policy/StellaOps.Policy.Engine | Policy Guild / src/Policy/StellaOps.Policy.Engine | Mirror bundle schema for policy packs not published; need bundle_id/provenance fields and sealed-mode rules. <br><br> Document artefact/deliverable for POLICY-AIRGAP-56-001 and publish location so downstream tasks can proceed. |
| P3 | PREP-POLICY-AIRGAP-56-002-DEPENDS-ON-56-001-B | DONE (2025-11-20) | Prep doc at `docs/modules/policy/prep/2025-11-20-policy-airgap-56-002-prep.md`; awaits schema hash from 56-001. | Policy Guild, Policy Studio Guild / src/Policy/StellaOps.Policy.Engine | Depends on 56-001 bundle import schema and DSSE signing profile. <br><br> Document artefact/deliverable for POLICY-AIRGAP-56-002 and publish location so downstream tasks can proceed. |
| P4 | PREP-POLICY-AIRGAP-57-001-REQUIRES-SEALED-MOD | DONE (2025-11-20) | Prep doc at `docs/modules/policy/prep/2025-11-20-policy-airgap-57-001-prep.md`; depends on 56-002 + WEB-OAS-61-002 envelope. | Policy Guild, AirGap Policy Guild / src/Policy/StellaOps.Policy.Engine | Requires sealed-mode contract (egress rules, error codes) after 56-002. <br><br> Document artefact/deliverable for POLICY-AIRGAP-57-001 and publish location so downstream tasks can proceed. |
| P5 | PREP-POLICY-AIRGAP-57-002-NEEDS-STALENESS-FAL | DONE (2025-11-20) | Prep doc at `docs/modules/policy/prep/2025-11-20-policy-airgap-57-002-prep.md`; awaits staleness metadata inputs. | Policy Guild, AirGap Time Guild / src/Policy/StellaOps.Policy.Engine | Needs staleness/fallback data contract from 57-001. <br><br> Document artefact/deliverable for POLICY-AIRGAP-57-002 and publish location so downstream tasks can proceed. |
@@ -49,6 +49,7 @@ Focus: Policy & Reasoning focus on Policy (phase I).
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-08 | Sprint created; awaiting staffing. | Planning |
| 2025-11-18 | Attempted EXPORT-CONSOLE-23-001 but blocked: no export bundle/schema or scheduler job contract for Console; requires API + signed manifest format before implementation. Marked remaining tasks BLOCKED pending lint/airgap/attest/Console contracts. | Policy Guild |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
## Decisions & Risks
- Dependency on Sprint 110.A AdvisoryAI remains; ensure upstream stays stable while export surface is added.

View File

@@ -10,7 +10,7 @@ Focus: Policy & Reasoning focus on Policy (phase III).
| # | Task ID & handle | State | Key dependency / next step | Owners |
| --- | --- | --- | --- | --- |
| P1 | PREP-POLICY-ENGINE-30-001-WAITING-ON-29-004-M | DOING (2025-11-20) | Due 2025-11-22 · Accountable: Policy Guild, Cartographer Guild / src/Policy/StellaOps.Policy.Engine | Policy Guild, Cartographer Guild / src/Policy/StellaOps.Policy.Engine | Waiting on 29-004 metrics/logging outputs to define overlay projection contract. <br><br> Document artefact/deliverable for POLICY-ENGINE-30-001 and publish location so downstream tasks can proceed. |
| P1 | PREP-POLICY-ENGINE-30-001-WAITING-ON-29-004-M | DONE (2025-11-22) | Due 2025-11-22 · Accountable: Policy Guild, Cartographer Guild / src/Policy/StellaOps.Policy.Engine | Policy Guild, Cartographer Guild / src/Policy/StellaOps.Policy.Engine | Overlay projection contract published at `docs/modules/policy/prep/2025-11-22-policy-engine-30-001-prep.md`; downstream tasks may proceed. |
| P2 | PREP-POLICY-ENGINE-30-002-SIMULATION-BRIDGE-C | DONE (2025-11-20) | Prep note at `docs/modules/policy/prep/2025-11-20-simulation-bridge-prep.md`; awaits 30-001 overlay hash. | Policy Guild, Cartographer Guild / src/Policy/StellaOps.Policy.Engine | Simulation bridge cannot proceed until 30-001 overlay schema lands. <br><br> Document artefact/deliverable for POLICY-ENGINE-30-002 and publish location so downstream tasks can proceed. |
| P3 | PREP-POLICY-ENGINE-30-003-CHANGE-EVENTS-DEPEN | DONE (2025-11-20) | Prep note at `docs/modules/policy/prep/2025-11-20-change-events-prep.md`; depends on 30-002 schema + Scheduler subjects. | Policy Guild, Scheduler Guild, Cartographer Guild / src/Policy/StellaOps.Policy.Engine | Change events depend on simulation bridge (30-002) outputs. <br><br> Document artefact/deliverable for POLICY-ENGINE-30-003 and publish location so downstream tasks can proceed. |
| P4 | PREP-POLICY-ENGINE-30-101-TRUST-WEIGHTING-UI- | DONE (2025-11-20) | Prep note at `docs/modules/policy/prep/2025-11-20-trust-weighting-prep.md`; waits on 30-003 outputs. | Policy Guild / src/Policy/StellaOps.Policy.Engine | Trust weighting UI/API depends on change events + overlays (30-003). <br><br> Document artefact/deliverable for POLICY-ENGINE-30-101 and publish location so downstream tasks can proceed. |
@@ -53,4 +53,6 @@ Focus: Policy & Reasoning focus on Policy (phase III).
| 2025-11-20 | Published prep artefacts for PREP-POLICY-ENGINE-30-002/003/30-101/31-001 under `docs/modules/policy/prep/`; marked P2P5 DONE. | Implementer |
| 2025-11-20 | Published prep artefacts for PREP-POLICY-ENGINE-31-002/32-101/33-101/34-101/35-201 under `docs/modules/policy/prep/`; marked P6P10 DONE. | Implementer |
| 2025-11-20 | Published prep artefacts for PREP-POLICY-ENGINE-38-201/40-001/40-002 under `docs/modules/policy/prep/`; marked P11P13 DONE. | Implementer |
| 2025-11-22 | Overlay projection prep captured at `docs/modules/policy/prep/2025-11-22-policy-engine-30-001-prep.md`; set P1 to DONE. | Project Mgmt |
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |

View File

@@ -7,26 +7,27 @@ Depends on: Sprint 150.A - Orchestrator
Summary: Notifications & Telemetry focus on Notifier (phase I).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
NOTIFY-ATTEST-74-001 | **DOING (2025-11-12)** | Create notification templates for verification failures, expiring attestations, key revocations, and transparency anomalies. | Notifications Service Guild, Attestor Service Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-ATTEST-74-001 | DONE (2025-11-16) | Create notification templates for verification failures, expiring attestations, key revocations, and transparency anomalies. | Notifications Service Guild, Attestor Service Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-ATTEST-74-002 | TODO | Wire notifications to key rotation/revocation events and transparency witness failures. Dependencies: NOTIFY-ATTEST-74-001. | Notifications Service Guild, KMS Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OAS-61-001 | **DOING (2025-11-12)** | Update notifier OAS with rules, templates, incidents, quiet hours endpoints using standard error envelope and examples. | Notifications Service Guild, API Contracts Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OAS-61-002 | TODO | Implement `/.well-known/openapi` discovery endpoint with scope metadata. Dependencies: NOTIFY-OAS-61-001. | Notifications Service Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OAS-62-001 | TODO | Provide SDK usage examples for rule CRUD, incident ack, and quiet hours; ensure SDK smoke tests. Dependencies: NOTIFY-OAS-61-002. | Notifications Service Guild, SDK Generator Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OAS-63-001 | TODO | Emit deprecation headers and Notifications templates for retiring notifier APIs. Dependencies: NOTIFY-OAS-62-001. | Notifications Service Guild, API Governance Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OBS-51-001 | TODO | Integrate SLO evaluator webhooks into Notifier rules (burn-rate breaches, health degradations) with templates, routing, and suppression logic. Provide sample policies and ensure imposed rule propagation. | Notifications Service Guild, Observability Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OBS-55-001 | TODO | Publish incident mode start/stop notifications with trace/evidence quick links, retention notes, and automatic escalation paths. Include quiet-hour overrides + legal compliance logging. Dependencies: NOTIFY-OBS-51-001. | Notifications Service Guild, Ops Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OAS-61-001 | DONE (2025-11-17) | Update notifier OAS with rules, templates, incidents, quiet hours endpoints using standard error envelope and examples. | Notifications Service Guild, API Contracts Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OAS-61-002 | DONE (2025-11-17) | Implement `/.well-known/openapi` discovery endpoint with scope metadata. Dependencies: NOTIFY-OAS-61-001. | Notifications Service Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OAS-62-001 | DONE (2025-11-17) | Provide SDK usage examples for rule CRUD, incident ack, and quiet hours; ensure SDK smoke tests. Dependencies: NOTIFY-OAS-61-002. | Notifications Service Guild, SDK Generator Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OAS-63-001 | DONE (2025-11-17) | Emit deprecation headers and Notifications templates for retiring notifier APIs. Dependencies: NOTIFY-OAS-62-001. | Notifications Service Guild, API Governance Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OBS-51-001 | DONE (2025-11-22) | Integrate SLO evaluator webhooks into Notifier rules (burn-rate breaches, health degradations) with templates, routing, and suppression logic. Provide sample policies and ensure imposed rule propagation. | Notifications Service Guild, Observability Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-OBS-55-001 | DONE (2025-11-22) | Publish incident mode start/stop notifications with trace/evidence quick links, retention notes, and automatic escalation paths. Include quiet-hour overrides + legal compliance logging. Dependencies: NOTIFY-OBS-51-001. | Notifications Service Guild, Ops Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-RISK-66-001 | TODO | Add notification triggers for risk severity escalation/downgrade events with profile metadata in payload. | Notifications Service Guild, Risk Engine Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-RISK-67-001 | TODO | Notify stakeholders when risk profiles are published, deprecated, or thresholds change. Dependencies: NOTIFY-RISK-66-001. | Notifications Service Guild, Policy Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-RISK-68-001 | TODO | Support per-profile routing rules, quiet hours, and dedupe for risk alerts; integrate with CLI/Console preferences. Dependencies: NOTIFY-RISK-67-001. | Notifications Service Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-DOC-70-001 | DONE (2025-11-02) | Document the split between legacy `src/Notify` libraries and the new `src/Notifier` runtime, updating architecture docs with rationale/cross-links. | Notifications Service Guild (src/Notifier/StellaOps.Notifier)
NOTIFY-AIRGAP-56-002 | DONE | Provide Bootstrap Pack notifier configurations with deterministic secrets handling and offline validation steps. Dependencies: NOTIFY-AIRGAP-56-001. | Notifications Service Guild, DevOps Guild (src/Notifier/StellaOps.Notifier)
## Status notes (2025-11-12 UTC)
## Status notes (2025-11-22 UTC)
- **NOTIFY-ATTEST-74-001** Template matrix (verification failure, expiring attestation, key revoke, witness anomaly) drafted; Section7 added to `docs/notifications/templates.md` plus cross-references in `notifications/overview.md` and `notifications/rules.md` so rule authors and operators use the canonical `tmpl-attest-*` suite; baseline template exports now live under `offline/notifier/templates/attestation/*.template.json`; waiting on Attestor schema freeze (due 2025-11-13) before locking copy and localization tokens.
- **NOTIFY-OAS-61-001** OpenAPI document restructure underway; shared error envelope + examples added, but `quietHours` and `incident` sections still need review with API Contracts Guild.
- **NOTIFY-OBS-51-001/NOTIFY-OBS-55-001** Telemetry SLO webhook schema frozen 2025-11-17; proceed with implementation; incident toggle contract to follow add-only evolution.
- **NOTIFY-RISK-66-001 → NOTIFY-RISK-68-001** Policy risk export v1 approved (read-only); proceed with notification wiring; history fields to arrive later additively.
- **NOTIFY-ATTEST-74-001** Template suite shipped; localized keys locked; see `docs/notifications/templates.md` §7 and offline exports under `offline/notifier/templates/attestation/`.
- **NOTIFY-OAS-61/62/63** OAS refresh, discovery endpoint, SDK examples, and deprecation headers are live.
- **NOTIFY-OBS-51-001** SLO webhook sink validated via filtered tests; TRX at `src/Notifier/StellaOps.Notifier/StellaOps.Notifier.Tests/TestResults/notifier-slo-tests.trx`.
- **NOTIFY-OBS-55-001** Incident-mode templates + importable rules shipped (`src/Notifier/StellaOps.Notifier/docs/incident-mode-rules.sample.json`); documented in `docs/notifications/templates.md` §8.
- **NOTIFY-RISK-66-001 → NOTIFY-RISK-68-001** Still waiting on POLICY-RISK-40-002 export; remain TODO.
## Milestones & dependencies
@@ -46,3 +47,4 @@ NOTIFY-AIRGAP-56-002 | DONE | Provide Bootstrap Pack notifier configurations wit
| 2025-11-12 19:32 | Updated `docs/notifications/architecture.md` rendering section to reference the new `tmpl-attest-*` suite so architecture + template docs stay in sync. | Notifications Service Guild |
| 2025-11-12 19:45 | Synced `docs/notifications/overview.md` and `docs/notifications/rules.md` with the attestation template requirements so operators and rule authors see the mandated keys. | Notifications Service Guild |
| 2025-11-12 20:05 | Added baseline template exports under `offline/notifier/templates/attestation/` (Slack/Email/Webhook variants) to seed Offline Kit bundles. | Notifications Service Guild |
| 2025-11-22 18:30 | Updated tracker: OAS 6163, OBS 51/55, ATTEST 74-001 marked DONE; incident-mode rules/templates published; SLO tests captured at `StellaOps.Notifier.Tests/TestResults/notifier-slo-tests.trx`. Risk tasks remain TODO pending POLICY-RISK-40-002 export. | Notifications Service Guild |

View File

@@ -942,7 +942,7 @@
| EXCITITOR-AIAI-31-003 | TODO | | SPRINT_110_ingestion_evidence | Excititor Observability Guild | | Telemetry/guardrail metrics follow chunk API. | EXCITITOR-AIAI-31-002 | EXAI0101 |
| EXCITITOR-AIAI-31-004 | TODO | | SPRINT_110_ingestion_evidence | Docs Guild · Excititor Guild | | Docs/OpenAPI alignment queued behind chunk API finalisation. | EXCITITOR-AIAI-31-002 | EXAI0101 |
| EXCITITOR-AIRGAP-56 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Air-gap + connector parity depend on schema + attestation readiness. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 |
| EXCITITOR-AIRGAP-56-001 | TODO | | SPRINT_0119_0001_0001_excititor_i | Excititor Core Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Core`) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Wire mirror bundle ingestion paths that preserve upstream digests, bundle IDs, and provenance metadata exactly so offline Advisory-AI/Lens deployments can replay evidence with AOC parity. | EXCITITOR-AIRGAP-56 | EXAG0101 |
| EXCITITOR-AIRGAP-56-001 | DOING (2025-11-22) | | SPRINT_0119_0001_0001_excititor_i | Excititor Core Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Core`) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Wire mirror bundle ingestion paths that preserve upstream digests, bundle IDs, and provenance metadata exactly so offline Advisory-AI/Lens deployments can replay evidence with AOC parity. | EXCITITOR-AIRGAP-56 | EXAG0101 |
| EXCITITOR-AIRGAP-57 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Same as -56 plus Evidence Locker | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 |
| EXCITITOR-AIRGAP-57-001 | TODO | | SPRINT_0119_0001_0001_excititor_i | Excititor AirGap Policy Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Core`) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Enforce sealed-mode policies that disable external connectors, emit actionable remediation errors, and record staleness annotations that Advisory AI can surface as “evidence freshness” signals. Depends on EXCITITOR-AIRGAP-56-001. | EXCITITOR-AIRGAP-57 | EXAG0101 |
| EXCITITOR-AIRGAP-58 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Same upstream | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 |
@@ -1217,16 +1217,16 @@
| NOTIFY-DOCS-0001 | DONE | 2025-11-05 | SPRINT_322_docs_modules_notify | Docs Guild | docs/modules/notify | Validate module README reflects Notifications Studio pivot and latest release notes. | NOTIFY-DOC-70-001 | DONO0102 |
| NOTIFY-DOCS-0002 | TODO | 2025-11-05 | SPRINT_322_docs_modules_notify | Docs Guild | docs/modules/notify | Pending NOTIFY-SVC-39-001..004 to document correlation/digests/simulation/quiet hours. | NOTIFY-SVC-39-004 | DONO0102 |
| NOTIFY-ENG-0001 | TODO | | SPRINT_322_docs_modules_notify | Module Team | docs/modules/notify | Keep implementation milestones aligned with `/docs/implplan/SPRINT_171_notifier_i.md` onward. | NOTY0103 | DONO0102 |
| NOTIFY-OAS-61-001 | DOING | | SPRINT_170_notifications_telemetry | Notifications Service Guild · API Governance Guild | docs/api/notifications | Update OpenAPI doc set (rule/incident endpoints) with new schemas + changelog. | NOTY0103 | NOOA0101 |
| NOTIFY-OAS-61-002 | TODO | | SPRINT_171_notifier_i | Notifications Service Guild · SDK Guild | docs/api/notifications | Provide SDK usage examples for rule CRUD, incident ack, and quiet hours; ensure SDK smoke tests. | NOTIFY-OAS-61-001 | NOOA0101 |
| NOTIFY-OAS-62-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Developer Portal Guild | docs/api/notifications | Publish `/docs/api/reference/notifications` auto-generated site; integrate with portal nav. | NOTIFY-OAS-61-002 | NOOA0101 |
| NOTIFY-OAS-63-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · SDK Generator Guild | docs/api/notifications | Provide CLI/UI quickstarts plus recipes referencing new endpoints. | NOTIFY-OAS-61-002 | NOOA0101 |
| NOTIFY-OBS-51-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Observability Guild | src/Notify/StellaOps.Notify | Implement telemetry SLO webhook schema + incident toggle contract. | NOTY0104 | NOOB0101 |
| NOTIFY-OBS-55-001 | TODO | | SPRINT_171_notifier_i | Notifications Service Guild · Ops Guild | src/Notify/StellaOps.Notify | Add override snapshots, legal compliance logging, and override audit events. | NOTIFY-OBS-51-001 | NOOB0101 |
| NOTIFY-OAS-61-001 | DONE (2025-11-17) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · API Governance Guild | docs/api/notifications | Update OpenAPI doc set (rule/incident endpoints) with new schemas + changelog. | NOTY0103 | NOOA0101 |
| NOTIFY-OAS-61-002 | DONE (2025-11-17) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · SDK Guild | docs/api/notifications | Provide SDK usage examples for rule CRUD, incident ack, and quiet hours; ensure SDK smoke tests. | NOTIFY-OAS-61-001 | NOOA0101 |
| NOTIFY-OAS-62-001 | DONE (2025-11-17) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Developer Portal Guild | docs/api/notifications | Publish `/docs/api/reference/notifications` auto-generated site; integrate with portal nav. | NOTIFY-OAS-61-002 | NOOA0101 |
| NOTIFY-OAS-63-001 | DONE (2025-11-17) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · SDK Generator Guild | docs/api/notifications | Provide CLI/UI quickstarts plus recipes referencing new endpoints. | NOTIFY-OAS-61-002 | NOOA0101 |
| NOTIFY-OBS-51-001 | DONE (2025-11-22) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Observability Guild | src/Notifier/StellaOps.Notifier | Integrate SLO evaluator webhooks into Notifier rules; templates/routing/suppression; sample policies. | NOTY0104 | NOOB0101 |
| NOTIFY-OBS-55-001 | DONE (2025-11-22) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Ops Guild | src/Notifier/StellaOps.Notifier | Incident mode start/stop notifications with evidence links, retention notes, quiet-hour overrides, legal logging. | NOTIFY-OBS-51-001 | NOOB0101 |
| NOTIFY-OPS-0001 | TODO | | SPRINT_322_docs_modules_notify | Ops Guild · Docs Guild | docs/modules/notify | Review notifier runbooks/observability assets after the next sprint demo and record findings. | NOTIFY-OBS-55-001 | NOOR0101 |
| NOTIFY-RISK-66-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Risk Engine Guild · Policy Guild | src/Notify/StellaOps.Notify | Policy/Risk metadata export required before implementation. | POLICY-RISK-40-002 | NORR0101 |
| NOTIFY-RISK-67-001 | TODO | | SPRINT_171_notifier_i | Notifications Service Guild · Policy Guild | src/Notify/StellaOps.Notify | Notify stakeholders when risk profiles are published, deprecated, or thresholds change. | NOTIFY-RISK-66-001 | NORR0101 |
| NOTIFY-RISK-68-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Risk Engine Guild · Policy Guild | src/Notify/StellaOps.Notify | Broadcast severity transitions with trace metadata and attach policy references. | NOTIFY-RISK-67-001 | NORR0101 |
| NOTIFY-RISK-66-001 | BLOCKED (2025-11-22) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Risk Engine Guild · Policy Guild | src/Notifier/StellaOps.Notifier | Policy/Risk metadata export (POLICY-RISK-40-002) not yet delivered. | POLICY-RISK-40-002 | NORR0101 |
| NOTIFY-RISK-67-001 | BLOCKED (2025-11-22) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Policy Guild | src/Notifier/StellaOps.Notifier | Depends on NOTIFY-RISK-66-001. | NOTIFY-RISK-66-001 | NORR0101 |
| NOTIFY-RISK-68-001 | BLOCKED (2025-11-22) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Risk Engine Guild · Policy Guild | src/Notifier/StellaOps.Notifier | Depends on NOTIFY-RISK-67-001. | NOTIFY-RISK-67-001 | NORR0101 |
| NOTIFY-SVC-37-001 | TODO | | SPRINT_172_notifier_ii | Notifications Service Guild | src/Notifier/StellaOps.Notifier | Define pack approval & policy notification contract, including OpenAPI schema, event payloads, resume token mechanics, and security guidance. | Align payload schema with PGMI0101 + ATEL0101 decisions | NOTY0103 |
| NOTIFY-SVC-37-002 | TODO | | SPRINT_172_notifier_ii | Notifications Service Guild | src/Notifier/StellaOps.Notifier | Implement secure ingestion endpoint, Mongo persistence (`pack_approvals`), idempotent writes, and audit trail for approval events. Dependencies: NOTIFY-SVC-37-001. | NOTIFY-SVC-37-001 | NOTY0103 |
| NOTIFY-SVC-37-003 | TODO | | SPRINT_172_notifier_ii | Notifications Service Guild | src/Notifier/StellaOps.Notifier | Deliver approval/policy templates, routing predicates, and channel dispatch (email/chat/webhook) with deterministic ordering plus ack gating. | NOTIFY-SVC-37-002 | NOTY0103 |
@@ -3438,16 +3438,16 @@
| NOTIFY-DOCS-0001 | DONE | 2025-11-05 | SPRINT_322_docs_modules_notify | Docs Guild | docs/modules/notify | Validate module README reflects Notifications Studio pivot and latest release notes. | NOTIFY-DOC-70-001 | DONO0102 |
| NOTIFY-DOCS-0002 | TODO | 2025-11-05 | SPRINT_322_docs_modules_notify | Docs Guild | docs/modules/notify | Pending NOTIFY-SVC-39-001..004 to document correlation/digests/simulation/quiet hours. | NOTIFY-SVC-39-004 | DONO0102 |
| NOTIFY-ENG-0001 | TODO | | SPRINT_322_docs_modules_notify | Module Team | docs/modules/notify | Keep implementation milestones aligned with `/docs/implplan/SPRINT_171_notifier_i.md` onward. | NOTY0103 | DONO0102 |
| NOTIFY-OAS-61-001 | DOING | | SPRINT_170_notifications_telemetry | Notifications Service Guild · API Governance Guild | docs/api/notifications | Update OpenAPI doc set (rule/incident endpoints) with new schemas + changelog. | NOTY0103 | NOOA0101 |
| NOTIFY-OAS-61-002 | TODO | | SPRINT_171_notifier_i | Notifications Service Guild · SDK Guild | docs/api/notifications | Provide SDK usage examples for rule CRUD, incident ack, and quiet hours; ensure SDK smoke tests. | NOTIFY-OAS-61-001 | NOOA0101 |
| NOTIFY-OAS-62-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Developer Portal Guild | docs/api/notifications | Publish `/docs/api/reference/notifications` auto-generated site; integrate with portal nav. | NOTIFY-OAS-61-002 | NOOA0101 |
| NOTIFY-OAS-63-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · SDK Generator Guild | docs/api/notifications | Provide CLI/UI quickstarts plus recipes referencing new endpoints. | NOTIFY-OAS-61-002 | NOOA0101 |
| NOTIFY-OBS-51-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Observability Guild | src/Notify/StellaOps.Notify | Implement telemetry SLO webhook schema + incident toggle contract. | NOTY0104 | NOOB0101 |
| NOTIFY-OBS-55-001 | TODO | | SPRINT_171_notifier_i | Notifications Service Guild · Ops Guild | src/Notify/StellaOps.Notify | Add override snapshots, legal compliance logging, and override audit events. | NOTIFY-OBS-51-001 | NOOB0101 |
| NOTIFY-OAS-61-001 | DONE (2025-11-17) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · API Governance Guild | docs/api/notifications | Update OpenAPI doc set (rule/incident endpoints) with new schemas + changelog. | NOTY0103 | NOOA0101 |
| NOTIFY-OAS-61-002 | DONE (2025-11-17) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · SDK Guild | docs/api/notifications | Provide SDK usage examples for rule CRUD, incident ack, and quiet hours; ensure SDK smoke tests. | NOTIFY-OAS-61-001 | NOOA0101 |
| NOTIFY-OAS-62-001 | DONE (2025-11-17) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Developer Portal Guild | docs/api/notifications | Publish `/docs/api/reference/notifications` auto-generated site; integrate with portal nav. | NOTIFY-OAS-61-002 | NOOA0101 |
| NOTIFY-OAS-63-001 | DONE (2025-11-17) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · SDK Generator Guild | docs/api/notifications | Provide CLI/UI quickstarts plus recipes referencing new endpoints. | NOTIFY-OAS-61-002 | NOOA0101 |
| NOTIFY-OBS-51-001 | DONE (2025-11-22) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Observability Guild | src/Notifier/StellaOps.Notifier | Integrate telemetry SLO webhook sink and routing into Notifier with templates and suppression. | NOTY0104 | NOOB0101 |
| NOTIFY-OBS-55-001 | DONE (2025-11-22) | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Ops Guild | src/Notifier/StellaOps.Notifier | Incident mode start/stop notifications with evidence links, retention notes, quiet-hour overrides, legal logging. | NOTIFY-OBS-51-001 | NOOB0101 |
| NOTIFY-OPS-0001 | TODO | | SPRINT_322_docs_modules_notify | Ops Guild · Docs Guild | docs/modules/notify | Review notifier runbooks/observability assets after the next sprint demo and record findings. | NOTIFY-OBS-55-001 | NOOR0101 |
| NOTIFY-RISK-66-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Risk Engine Guild · Policy Guild | src/Notify/StellaOps.Notify | Policy/Risk metadata export required before implementation. | POLICY-RISK-40-002 | NORR0101 |
| NOTIFY-RISK-67-001 | TODO | | SPRINT_171_notifier_i | Notifications Service Guild · Policy Guild | src/Notify/StellaOps.Notify | Notify stakeholders when risk profiles are published, deprecated, or thresholds change. | NOTIFY-RISK-66-001 | NORR0101 |
| NOTIFY-RISK-68-001 | TODO | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Risk Engine Guild · Policy Guild | src/Notify/StellaOps.Notify | Broadcast severity transitions with trace metadata and attach policy references. | NOTIFY-RISK-67-001 | NORR0101 |
| NOTIFY-RISK-66-001 | TODO | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Risk Engine Guild · Policy Guild | src/Notifier/StellaOps.Notifier | Policy/Risk metadata export required before implementation. | POLICY-RISK-40-002 | NORR0101 |
| NOTIFY-RISK-67-001 | TODO | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Policy Guild | src/Notifier/StellaOps.Notifier | Notify stakeholders when risk profiles are published, deprecated, or thresholds change. | NOTIFY-RISK-66-001 | NORR0101 |
| NOTIFY-RISK-68-001 | TODO | | SPRINT_0171_0001_0001_notifier_i | Notifications Service Guild · Risk Engine Guild · Policy Guild | src/Notifier/StellaOps.Notifier | Broadcast severity transitions with trace metadata and attach policy references. | NOTIFY-RISK-67-001 | NORR0101 |
| NOTIFY-SVC-37-001 | TODO | | SPRINT_172_notifier_ii | Notifications Service Guild | src/Notifier/StellaOps.Notifier | Define pack approval & policy notification contract, including OpenAPI schema, event payloads, resume token mechanics, and security guidance. | Align payload schema with PGMI0101 + ATEL0101 decisions | NOTY0103 |
| NOTIFY-SVC-37-002 | TODO | | SPRINT_172_notifier_ii | Notifications Service Guild | src/Notifier/StellaOps.Notifier | Implement secure ingestion endpoint, Mongo persistence (`pack_approvals`), idempotent writes, and audit trail for approval events. Dependencies: NOTIFY-SVC-37-001. | NOTIFY-SVC-37-001 | NOTY0103 |
| NOTIFY-SVC-37-003 | TODO | | SPRINT_172_notifier_ii | Notifications Service Guild | src/Notifier/StellaOps.Notifier | Deliver approval/policy templates, routing predicates, and channel dispatch (email/chat/webhook) with deterministic ordering plus ack gating. | NOTIFY-SVC-37-002 | NOTY0103 |

View File

@@ -605,5 +605,6 @@ concelier:
1. **MVP**: Red Hat (CSAF), SUSE (CSAF), Ubuntu (USN JSON), OSV; JSON export.
2. **Add**: GHSA GraphQL, Debian (DSA HTML/JSON), Alpine secdb; Trivy DB export.
3. **Attestation handoff**: integrate with **Signer/Attestor** (optional).
- Advisory evidence attestation parameters and path rules are documented in `docs/modules/concelier/attestation.md`.
4. **Scale & diagnostics**: provider dashboards, staleness alerts, export cache reuse.
5. **Offline kit**: endtoend verified bundles for airgap.

View File

@@ -0,0 +1,30 @@
# Concelier Advisory Evidence Attestation
## Purpose
- Describe how Concelier returns attestation claims for advisory evidence bundles so downstream services (Advisory AI, Attestor, Console) can verify provenance.
## Endpoint
- `GET /vuln/evidence/advisories/{advisoryKey}`
- Authentication/tenant headers follow standard Concelier rules (`X-Stella-Tenant` or `tenant` query; authority policies apply).
- Response payload: `AdvisoryEvidenceResponse { advisoryKey, records[], attestation? }`
## Attestation parameters (query)
- `bundlePath` (required to enable attestation): Relative or absolute path to evidence bundle tar.gz. Relative paths are resolved under the configured evidence root (`concelier:evidence:root`). Paths outside this root are rejected.
- `manifestPath` (optional): Defaults to sibling `manifest.json` next to the bundle.
- `transparencyPath` (optional): Defaults to sibling `transparency.json` next to the bundle.
- `pipelineVersion` (optional): Defaults to `concelier:evidence:pipelineVersion` (e.g., `git:<sha>`).
## Behavior
- When `bundlePath` is omitted, the endpoint returns evidence records only (attestation is `null`).
- When provided, Concelier builds claims via `EvidenceBundleAttestationBuilder` using the manifest and optional transparency payload; tenant must be lowercase per scope note.
- Path safety: All resolved files must live under the evidence root; traversal attempts or missing files silently skip attestation (response remains valid without claims).
## Configuration
- `concelier:evidence:root` (default `out/evidence/bundles`, resolved absolute).
- `concelier:evidence:defaultManifestFileName` (default `manifest.json`).
- `concelier:evidence:defaultTransparencyFileName` (default `transparency.json`).
- `concelier:evidence:pipelineVersion` (default `git:unknown`).
## References
- Evidence Locker attestation scope: `docs/modules/evidence-locker/attestation-scope-note.md`.
- Implementation: `src/Concelier/StellaOps.Concelier.WebService/Program.cs`, `StellaOps.Concelier.Core/Attestation/EvidenceBundleAttestationBuilder.cs`.

View File

@@ -0,0 +1,29 @@
# Concelier OAS & Observability Prep (61-001..63-001, 51-001..55-001)
Status: **Ready for implementation** (2025-11-22)
Owners: Concelier Core Guild · API Contracts Guild · DevOps/Observability Guilds
Scope: Freeze the API/SDK contracts and observability envelopes for LNM search/timeline APIs so downstream SDK, governance, and incident flows can proceed without schema churn.
## Inputs
- Frozen LNM payload schema: `docs/modules/concelier/link-not-merge-schema.md` (2025-11-17).
- Event contract: `docs/modules/concelier/events/advisory.observation.updated@1.md`.
- Registry/worker orchestration contract: `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`.
## Deliverables
- OpenAPI source stub for LNM + timeline surfaces recorded at `docs/modules/concelier/openapi/lnm-api.yaml` (paths enumerated; examples outlined below).
- SDK example library checklist covering `searchAdvisories`, `searchLinksets`, `getTimeline`, `getObservationById`; response bodies aligned to frozen schema; no consensus/merge fields.
- Observability contract (metrics/logs/traces):
- Metrics: `concelier_ingest_latency_seconds`, `concelier_linkset_conflicts_total`, `concelier_timeline_emit_lag_seconds`, `concelier_api_requests_total{route,tenant,status}` with burn-rate alert examples.
- Logs: structured fields `tenantId`, `advisoryKey`, `linksetId`, `timelineCursor`, `egressPolicy`.
- Traces: span names for `lnm.search`, `lnm.timeline`, `lnm.linkset-resolve` with baggage keys `tenant-id`, `request-id`.
- Incident/observability hooks: timeline/attestation enrichment notes for OBS-54/55 including DSSE envelope hash field and sealed-mode redaction rules.
## Acceptance Criteria
- Request/response shapes for `/api/v1/lnm/advisories`, `/api/v1/lnm/linksets`, `/api/v1/lnm/timeline` documented with required query params (`tenantId`, `productKey`, `offset`, `limit`, `sort`, `includeTimeline=true|false`).
- All responses MUST include `provenance` block (source, fetchedAt, digest, evidenceBundleId) and forbid consensus/merge fields.
- Metrics/logs names and labels are deterministic and lowercase; alert examples reference burn-rate SLOs.
- File path above is referenced from sprint trackers; any future schema edits require bumping version/comment in this prep doc.
## Notes
- This prep satisfies PREP-CONCELIER-OAS-61-001/002/62-001/63-001 and PREP-CONCELIER-OBS-51-001/52-001/53-001/54-001/55-001.
- No external dependencies remaining; downstream tasks may proceed using the stubbed OpenAPI and observability contracts here.

View File

@@ -0,0 +1,30 @@
# Excititor Air-Gap Prep (56-001, 57-001, 58-001)
Status: **Ready for implementation** (2025-11-22)
Owners: Excititor Core Guild · AirGap Policy Guild · Evidence Locker Guild
Scope: Define ingestion/egress contracts for Excititor when operating in sealed/offline environments and align with mirror bundle + Evidence Locker artifacts.
## Inputs
- Mirror bundle schema (thin) from `docs/modules/mirror/assembler.md`.
- Evidence Locker attestation contract: `docs/modules/evidence-locker/attestation-contract.md`.
- Link-Not-Merge schema for advisory evidence: `docs/modules/concelier/link-not-merge-schema.md`.
## Deliverables
- Ingestion envelope for `POST /airgap/vex/import`:
- Fields: `bundleId`, `mirrorGeneration`, `signedAt`, `publisher`, `payloadHash`, `payloadUrl?` (offline tar path), `signature`, `transparencyLog?`.
- Validation: deterministic hash of NDJSON payloads; must reject mixed tenants; clock-skew tolerance ±5s.
- Sealed-mode error catalog (57-001): `AIRGAP_EGRESS_BLOCKED`, `AIRGAP_PAYLOAD_STALE`, `AIRGAP_SIGNATURE_MISSING`, `AIRGAP_SOURCE_UNTRUSTED`; each with HTTP 4xx mapping and remediation text.
- Notification hooks (58-001): timeline events `airgap.import.started/completed/failed` with attributes `{tenantId,bundleId,generation,stalenessSeconds}`; link to Evidence Locker bundle ID for audit.
- Determinism rules: sort imported observations by `advisoryKey` then `productKey`; write timeline events in the same order; all timestamps UTC ISO-8601.
- Connector trust (CONN-TRUST-01-001):
- Trusted signer manifests reuse `docs/modules/excititor/schemas/connector-signer-metadata.schema.json`; require `fingerprint`, `issuer`, `validFrom/To`, `allowedProfiles`, `bundleHash`.
- Validation: fail import with `AIRGAP_SOURCE_UNTRUSTED` when signer fingerprint not in manifest, signature algorithm not in `{rsa-pss-sha256, ecdsa-p256-sha256, gost-r3410-2012-256}`, or bundle hash mismatch.
- Offline parity: store signer manifests alongside mirror bundle under `mirror/signers/` and include SHA256 in `SHA256SUMS.dsse`.
## Acceptance Criteria
- API shapes captured in this prep are referenced from Sprint 0119 Delivery Tracker; no further blockers for Excititor AirGap tasks.
- Error catalog and timeline events documented and consumed by downstream Policy/AirGap controller work.
- Import path validated against mirror bundle schema; mismatch should raise `AIRGAP_PAYLOAD_STALE`.
## Notes
- Satisfies PREP-EXCITITOR-AIRGAP-56-001, PREP-EXCITITOR-AIRGAP-57-001, and PREP-EXCITITOR-AIRGAP-58-001.

View File

@@ -0,0 +1,27 @@
# Attestation Verifier Rehearsal — Excititor
Status: **Ready for implementation** (2025-11-22)
Owners: Excititor Attestation Guild · Evidence Locker Guild
Scope: Dry-run `IVexAttestationVerifier` against current Evidence Locker bundles to ensure Excititor attestation endpoints ship with deterministic verification.
## Test Matrix
- Inputs: Evidence Bundle v1 sample (`docs/samples/evidence-bundle/*`), mirror bundle thin sample (`out/mirror/thin/mirror-thin-m0-sample.tar.gz`).
- Verification steps:
1. Validate DSSE envelope signature and Rekor entry (if present); offline mode skips transparency but records `rekorSkipped=true`.
2. Verify manifest hash tree against payload NDJSON files; fail on first mismatch.
3. Assert policy hash matches Policy Engine overlay hash (placeholder `policyHash` captured for now).
4. Emit structured result JSON: `{bundleId, verified, dsseVerified, transparencyChecked, manifestRoot, failures[]}`.
- Determinism: sorted failure list, timestamps set to supplied `--as-of` flag.
## Deliverables
- Harness entry point: `tools/attestation/verifier-rehearsal.sh` (script stub path reserved).
- Sample output recorded at `docs/modules/excititor/prep/artifacts/2025-11-22-attestation-rehearsal.json` (to be produced in implementation).
- Logging fields to surface in Excititor: `attestationBundleId`, `evidenceBundleId`, `verified`, `failureCode`, `tenantId`.
## Acceptance Criteria
- Rehearsal script runs offline using bundled samples and exits non-zero on any verification failure.
- Output schema above is referenced by Excititor API tests and Policy attest replay tasks.
- Downstream tasks EXCITITOR-GRAPH-21-00x and attestation endpoints can rely on this contract.
## Notes
- Satisfies PREP-ATTESTATION-VERIFIER-REHEARSAL-EXCITITOR.

View File

@@ -0,0 +1,33 @@
# Findings Ledger Prep — 29-008, 34-101, AIRGAP-56-001
Status: **Ready for implementation** (2025-11-22)
Owners: Findings Ledger Guild · Observability Guild · AirGap Time Guild · Orchestrator Guild
Scope: Provide the missing contracts needed to unblock LEDGER-29-008 load/replay, LEDGER-34-101 orchestrator export linkage, and LEDGER-AIRGAP-56-001 bundle provenance recording.
## Observability (LEDGER-29-008)
- Metrics schema locked:
- `ledger_projection_lag_seconds{tenant}` (gauge)
- `ledger_write_duration_seconds_bucket` (histogram)
- `ledger_events_total{tenant,kind}` (counter)
- Alert: burn-rate 4xx/5xx on ingestion path >2% over 5m/1h.
- Log fields: `tenantId`, `requestId`, `projectionCheckpoint`, `bundleId?`, `attestationId?`, `operation`.
- Trace spans: `ledger.write`, `ledger.replay`, `ledger.restore` with baggage `tenant-id`, `bundle-id`.
## Orchestrator export linkage (LEDGER-34-101)
- Export payload shape (from Orchestrator Sprint 150.A):
- `runId` (uuid), `jobType`, `artifactHash`, `policyHash`, `startedAt`, `completedAt`, `status`, `manifestPath`, `logsPath`.
- Ledger integration rule: store export rows under collection `orchestrator_exports` with index `(artifactHash, runId)`; anchor Merkle root into ledger timeline entry `ledger_export` referencing above fields.
## AirGap provenance (LEDGER-AIRGAP-56-001)
- Mirror bundle contract alignment:
- fields recorded per import: `bundleId`, `mirrorGeneration`, `merkleRoot`, `timeAnchor`, `publisher`, `hashAlgorithm`, `contents[]` (sha256 of NDJSON segments).
- determinism: imports sorted by `bundleId`; all timestamps UTC.
- API for recording import: `POST /internal/ledger/airgap-import` with payload above; respond 202 + `ledgerEntryId`.
## Acceptance Criteria
- Metrics/log/logging names frozen as above and added to `docs/modules/findings-ledger/observability.md` in next implementation step.
- Orchestrator export payload shape referenced by both Ledger and Orchestrator tasks; no missing fields for audit.
- AirGap import payload is deterministic and replays without external network requirements.
## Notes
- Satisfies PREP-LEDGER-29-008-AWAIT-OBSERVABILITY-SCHEMA, PREP-LEDGER-34-101-ORCHESTRATOR-LEDGER-EXPORT, and PREP-LEDGER-AIRGAP-56-001-MIRROR-BUNDLE-SCHEM.

View File

@@ -0,0 +1,22 @@
# Policy Export · Console 23-001 Prep
Status: **Ready for implementation** (2025-11-22)
Owners: Policy Guild · Scheduler Guild · Observability Guild
Scope: Define the export bundle + scheduler job surface needed for Console export task 23-001.
## Export Bundle Contract
- Payload: NDJSON of advisory and VEX observations filtered by tenant + product set; include `provenance` block with `source`, `fetchedAt`, `digest`, `evidenceBundleId`.
- Envelope: `bundleId`, `createdAt`, `policyHash`, `schemaVersion`, `itemsSha256`, optional `transparency` entry.
- Determinism: sort items by `observationId`; timestamps truncated to seconds; hashes sha256 lower-case hex.
## Scheduler Job Shape
- `jobType`: `console-export` with fields `tenantId`, `bundleId`, `filters`, `destinationUri` (file:// or s3://), `retryPolicy`, `notificationChannel`.
- Status transitions: `queued → running → completed/failed`; progress fields `exportedCount`, `failedCount`.
- Observability: metrics `policy_console_export_jobs_total{status}`, `policy_console_export_duration_seconds`, logs with `bundleId` and `destinationUri`.
## Acceptance Criteria
- Job shape and bundle envelope above referenced from Sprint 123 Delivery Tracker; no other blocking dependencies.
- Export artefacts can be consumed offline; notification optional.
## Notes
- Satisfies PREP-EXPORT-CONSOLE-23-001-MISSING-EXPORT-BUN.

View File

@@ -0,0 +1,24 @@
# Policy AirGap 56-001 Prep — Mirror Bundle Schema
Status: **Ready for implementation** (2025-11-22)
Owners: Policy Guild · AirGap Policy Guild
Scope: Lock the mirror bundle schema required for policy pack distribution in sealed mode.
## Bundle Schema
- Envelope: `bundleId`, `schemaVersion` (`policy-mirror-v1`), `createdAt`, `publisher`, `signature`, `transparencyLog?`.
- Contents array entries:
- `policyHash`, `policyName`, `version`, `targetProducts[]`, `scope` (tenant/portfolio), `dependencies[]` (other bundleIds), `config` (immutable), `evidenceBundleId?`.
- Hashing: manifest sha256 over sorted file list (`policies/*.rego`, `overlays/*.json`), recorded as `manifestSha256`.
- Staleness: `validUntil` and `timeAnchor` fields; sealed-mode must reject if `now > validUntil` or time drift > 300s.
## Determinism & Transport
- Files stored in tarball with POSIX mtime `2025-01-01T00:00:00Z` and uid/gid 0.
- Manifest path fixed to `MANIFEST.json`; entries sorted alphabetically.
- No external fetches permitted during import.
## Acceptance Criteria
- Schema above referenced by Policy AirGap tasks and aligns with Mirror bundle contract (`docs/modules/mirror/assembler.md`).
- Import validators know failure codes: `POLICY_BUNDLE_STALE`, `POLICY_BUNDLE_SIGNATURE_INVALID`, `POLICY_BUNDLE_SCHEMA_MISMATCH`.
## Notes
- Completes PREP-POLICY-AIRGAP-56-001-MIRROR-BUNDLE-SCHEM.

View File

@@ -0,0 +1,24 @@
# Policy Engine 30-001 Prep — Overlay Projection
Status: **Ready for implementation** (2025-11-22)
Owners: Policy Guild · Cartographer Guild
Scope: Freeze overlay projection contract needed for Policy Engine phase III.
## Inputs
- Path/scope schema: `docs/modules/policy/prep/2025-11-20-policy-engine-29-002-prep.md`.
- Metrics/log schema: `docs/modules/policy/prep/2025-11-20-policy-engine-29-004-prep.md`.
## Overlay Projection Contract
- Input: evaluation records `{tenantId, policyId, pathScope[], evidenceDigest, decision, reasons[]}`.
- Output overlay entry:
- `overlayId` (deterministic hash of `tenantId+policyId+pathScope+evidenceDigest`)
- `subject` (`purl` or `pkg` tuple), `pathScope`, `decision`, `rationale`, `inputs` (evidence digests), `policyVersion`, `createdAt`.
- Determinism: pathScope sorted; reasons sorted by `code`; timestamps set to evaluation clock.
- Export shape for downstream components via `/overlays/{overlayId}` and `/overlays/search` with paging.
## Acceptance Criteria
- Overlay schema above referenced in Sprint 125 and 0125 trackers; downstream simulation/bridge tasks can consume it without further schema.
- Any future field additions require version bump `overlaySchemaVersion`.
## Notes
- Completes PREP-POLICY-ENGINE-30-001-WAITING-ON-29-004-M.

View File

@@ -201,3 +201,39 @@ Rekor entry: {{link "Transparency log" payload.links.rekor}}
---
> **Imposed rule reminder:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
---
## 8. Incident mode templates (NOTIFY-OBS-55-001)
Incident toggles are high-noise events that must pierce quiet hours and include audit-ready context. Use dedicated templates so downstream tooling can distinguish activation vs. recovery and surface the required evidence.
**Required context keys**
- `payload.incidentId`, `payload.reason`, `payload.startedAt` / `payload.stoppedAt`.
- `payload.links.trace` (root cause trace/span), `payload.links.evidence` (timeline/export bundle), `payload.links.timeline`.
- `payload.retentionDays` (active) and `payload.retentionBaselineDays` (post-incident).
- `payload.quietHoursOverride` (boolean) to justify bypassing quiet hours.
- `payload.legal.jurisdiction`, `payload.legal.ticket`, `payload.legal.logPath` for compliance logging.
**Template keys**
- `tmpl-incident-start` — activation notice.
- `tmpl-incident-stop` — recovery/cleanup notice.
**Slack sample (start)**
```hbs
:rotating_light: Incident mode activated for {{payload.incidentId}}
Reason: {{payload.reason}}
Trace: {{link "root span" payload.links.trace}} · Evidence: {{link "bundle" payload.links.evidence}}
Retention extended to {{payload.retentionDays}} days (baseline {{payload.retentionBaselineDays}})
Quiet hours overridden: {{payload.quietHoursOverride}}
Legal: {{payload.legal.jurisdiction}} (ticket {{payload.legal.ticket}})
```
**Email sample (stop)**
```hbs
<h2>Incident mode cleared: {{payload.incidentId}}</h2>
<p>Stopped at {{payload.stoppedAt}} — retention reset to {{payload.retentionBaselineDays}} days.</p>
<p>Timeline: {{link "view timeline" payload.links.timeline}} · Audit log: {{payload.legal.logPath}}</p>
```
See `src/Notifier/StellaOps.Notifier/docs/incident-mode-rules.sample.json` for ready-to-import rules referencing these templates with quiet-hour overrides and legal logging metadata.

View File

@@ -1,8 +1,8 @@
# Samples Prep — PREP-SAMPLES-LNM-22-001
# Samples Prep — PREP-SAMPLES-LNM-22-001 / 22-002
Status: **Ready for implementation** (2025-11-20)
Owners: Samples Guild · Concelier Guild
Scope: Produce finalized advisory linkset samples aligned to frozen Concelier linkset schema (LNM-21-002 freeze on 2025-11-20).
Status: **Ready for implementation** (2025-11-22)
Owners: Samples Guild · Concelier Guild · Excititor Guild
Scope: Produce finalized advisory linkset samples aligned to frozen Concelier linkset schema (LNM-21-002 freeze on 2025-11-20) and extend the same fixture set with Excititor observation/VEX payloads for phase 22-002.
## Inputs
- Link-Not-Merge schema: `docs/modules/concelier/link-not-merge-schema.md` (frozen 2025-11-20) and samples under `docs/samples/lnm/`.
@@ -15,6 +15,14 @@ Scope: Produce finalized advisory linkset samples aligned to frozen Concelier li
- Each file accompanied by `.sha256` hash.
- README (`samples/linkset/README.md`) describing schema version, generation seed, and deterministic ordering rules.
## Excititor extension (PREP-SAMPLES-LNM-22-002)
- Extend NDJSON fixtures with Excititor-origin observations:
- `lnm-excititor-vex-sample.ndjson` — 250 Excititor VEX chunks with sealed-mode flags and provenance hashes.
- `lnm-excititor-observations.ndjson` — 250 observation records showing worker/runtime traces.
- Determinism: reuse seed above; order by `observationId`; timestamps fixed to `2025-01-02T00:05:00Z`.
- Additional hashes recorded alongside existing `.sha256` files.
- Document Excititor-specific provenance fields (chunkId, evidenceBundleId, tenantId) in `samples/linkset/README.md`.
## Determinism
- Generation seed: `2025-01-01T00:00:00Z` (use in faker/RNG).
- Sort records by `observationId` before writing; timestamps set to deterministic `2025-01-02T00:00:00Z` for all entries.

View File

@@ -1,4 +1,4 @@
# Concelier · AGENTS Charter (Sprint 01120113)
# Concelier · AGENTS Charter (Sprint 01120114)
## Module Scope & Working Directory
- Working directory: `src/Concelier/**` (WebService, __Libraries, Storage.Mongo, analyzers, tests, seed-data). Do not edit other modules unless explicitly referenced by this sprint.
@@ -17,7 +17,9 @@
- `docs/modules/concelier/architecture.md`
- `docs/modules/concelier/link-not-merge-schema.md`
- `docs/provenance/inline-dsse.md` (for provenance anchors/DSSE notes)
- Any sprint-specific ADRs/notes linked from `docs/implplan/SPRINT_0112_0001_0001_concelier_i.md` or `SPRINT_0113_0001_0002_concelier_ii.md`.
- `docs/modules/concelier/prep/2025-11-22-oas-obs-prep.md` (OAS + observability prep)
- `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md` (orchestrator registry/control contracts)
- Any sprint-specific ADRs/notes linked from `docs/implplan/SPRINT_0112_0001_0001_concelier_i.md`, `SPRINT_0113_0001_0002_concelier_ii.md`, or `SPRINT_0114_0001_0003_concelier_iii.md`.
## Working Agreements
- **Aggregation-Only Contract (AOC):** no derived semantics in ingestion; enforce via `AOCWriteGuard` and analyzers. Raw observations are append-only; linksets carry correlations/conflicts only.

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text.Json;
using System.Text.Json.Serialization;
using StellaOps.Concelier.Core.Attestation;
using StellaOps.Concelier.RawModels;
namespace StellaOps.Concelier.WebService.Contracts;
@@ -89,7 +90,8 @@ public sealed record AdvisoryRawListResponse(
public sealed record AdvisoryEvidenceResponse(
[property: JsonPropertyName("advisoryKey")] string AdvisoryKey,
[property: JsonPropertyName("records")] IReadOnlyList<AdvisoryRawRecordResponse> Records);
[property: JsonPropertyName("records")] IReadOnlyList<AdvisoryRawRecordResponse> Records,
[property: JsonPropertyName("attestation")] AttestationClaims? Attestation);
public sealed record AdvisoryRawProvenanceResponse(
[property: JsonPropertyName("id")] string Id,

View File

@@ -0,0 +1,56 @@
using System.ComponentModel.DataAnnotations;
using StellaOps.Concelier.Storage.Mongo.Orchestrator;
namespace StellaOps.Concelier.WebService.Contracts;
public sealed record OrchestratorRegistryRequest(
[property: Required] string ConnectorId,
[property: Required] string Source,
[property: Required] string[] Capabilities,
[property: Required] string AuthRef,
[property: Required] OrchestratorScheduleDto Schedule,
[property: Required] OrchestratorRatePolicyDto RatePolicy,
[property: Required] string[] ArtifactKinds,
[property: Required] string LockKey,
[property: Required] OrchestratorEgressGuardDto EgressGuard);
public sealed record OrchestratorScheduleDto(
string Cron,
string TimeZone,
int MaxParallelRuns,
int MaxLagMinutes);
public sealed record OrchestratorRatePolicyDto(
int Rpm,
int Burst,
int CooldownSeconds);
public sealed record OrchestratorEgressGuardDto(
string[] Allowlist,
bool AirgapMode);
public sealed record OrchestratorHeartbeatRequest(
[property: Required] string ConnectorId,
[property: Required] Guid RunId,
[property: Required] long Sequence,
[property: Required] OrchestratorHeartbeatStatus Status,
int? Progress,
int? QueueDepth,
string? LastArtifactHash,
string? LastArtifactKind,
string? ErrorCode,
int? RetryAfterSeconds,
DateTimeOffset? TimestampUtc);
public sealed record OrchestratorCommandRequest(
[property: Required] string ConnectorId,
[property: Required] Guid RunId,
[property: Required] long Sequence,
[property: Required] OrchestratorCommandKind Command,
OrchestratorThrottleOverrideDto? Throttle,
OrchestratorBackfillRangeDto? Backfill,
DateTimeOffset? ExpiresAt);
public sealed record OrchestratorThrottleOverrideDto(int? Rpm, int? Burst, int? CooldownSeconds, DateTimeOffset? ExpiresAt);
public sealed record OrchestratorBackfillRangeDto(string? FromCursor, string? ToCursor);

View File

@@ -21,6 +21,8 @@ public sealed class ConcelierOptions
public AdvisoryChunkOptions AdvisoryChunks { get; set; } = new();
public EvidenceBundleOptions Evidence { get; set; } = new();
public StellaOpsCryptoOptions Crypto { get; } = new();
public sealed class StorageOptions
@@ -172,4 +174,20 @@ public sealed class ConcelierOptions
public int CacheDurationSeconds { get; set; } = 30;
}
public sealed class EvidenceBundleOptions
{
public bool Enabled { get; set; } = true;
public string Root { get; set; } = System.IO.Path.Combine("out", "evidence", "bundles");
public string? DefaultManifestFileName { get; set; } = "manifest.json";
public string? DefaultTransparencyFileName { get; set; } = "transparency.json";
public string PipelineVersion { get; set; } = "git:unknown";
[JsonIgnore]
public string RootAbsolute { get; internal set; } = string.Empty;
}
}

View File

@@ -19,6 +19,7 @@ public static class ConcelierOptionsPostConfigure
options.Authority ??= new ConcelierOptions.AuthorityOptions();
options.Features ??= new ConcelierOptions.FeaturesOptions();
options.Evidence ??= new ConcelierOptions.EvidenceBundleOptions();
var authority = options.Authority;
if (string.IsNullOrWhiteSpace(authority.ClientSecret)
@@ -69,5 +70,29 @@ public static class ConcelierOptionsPostConfigure
{
mirror.MirrorDirectoryName = "mirror";
}
var evidence = options.Evidence;
if (string.IsNullOrWhiteSpace(evidence.Root))
{
evidence.Root = Path.Combine("out", "evidence", "bundles");
}
var evidenceRoot = evidence.Root;
if (!Path.IsPathRooted(evidenceRoot))
{
evidenceRoot = Path.Combine(contentRootPath, evidenceRoot);
}
evidence.RootAbsolute = Path.GetFullPath(evidenceRoot);
if (string.IsNullOrWhiteSpace(evidence.DefaultManifestFileName))
{
evidence.DefaultManifestFileName = "manifest.json";
}
if (string.IsNullOrWhiteSpace(evidence.DefaultTransparencyFileName))
{
evidence.DefaultTransparencyFileName = "transparency.json";
}
}
}

View File

@@ -137,6 +137,9 @@ public static class ConcelierOptionsValidator
options.Mirror ??= new ConcelierOptions.MirrorOptions();
ValidateMirror(options.Mirror);
options.Evidence ??= new ConcelierOptions.EvidenceBundleOptions();
ValidateEvidence(options.Evidence);
options.AdvisoryChunks ??= new ConcelierOptions.AdvisoryChunkOptions();
ValidateAdvisoryChunks(options.AdvisoryChunks);
}
@@ -312,4 +315,22 @@ public static class ConcelierOptionsValidator
throw new InvalidOperationException("Advisory chunk cacheDurationSeconds must be greater than or equal to zero.");
}
}
private static void ValidateEvidence(ConcelierOptions.EvidenceBundleOptions evidence)
{
if (string.IsNullOrWhiteSpace(evidence.Root))
{
throw new InvalidOperationException("Evidence bundle root must be configured.");
}
if (string.IsNullOrWhiteSpace(evidence.RootAbsolute))
{
throw new InvalidOperationException("Evidence bundle root could not be resolved.");
}
if (string.IsNullOrWhiteSpace(evidence.PipelineVersion))
{
throw new InvalidOperationException("Evidence bundle pipelineVersion must be provided.");
}
}
}

View File

@@ -55,6 +55,7 @@ using StellaOps.Concelier.Storage.Mongo.Advisories;
using StellaOps.Concelier.Storage.Mongo.Aliases;
using StellaOps.Provenance.Mongo;
using StellaOps.Concelier.Core.Attestation;
using StellaOps.Concelier.Storage.Mongo.Orchestrator;
var builder = WebApplication.CreateBuilder(args);
@@ -398,6 +399,162 @@ app.MapGet("/.well-known/openapi", ([FromServices] OpenApiDiscoveryDocumentProvi
}
}).WithName("GetConcelierOpenApiDocument");
var orchestratorGroup = app.MapGroup("/internal/orch");
if (authorityConfigured)
{
orchestratorGroup.RequireAuthorization();
}
orchestratorGroup.MapPost("/registry", async (
HttpContext context,
[FromBody] OrchestratorRegistryRequest request,
[FromServices] IOrchestratorRegistryStore store,
TimeProvider timeProvider,
CancellationToken cancellationToken) =>
{
if (!TryResolveTenant(context, requireHeader: true, out var tenant, out var tenantError))
{
return tenantError;
}
if (string.IsNullOrWhiteSpace(request.ConnectorId) || string.IsNullOrWhiteSpace(request.Source))
{
return Problem(context, "connectorId and source are required", StatusCodes.Status400BadRequest, ProblemTypes.Validation, "Provide connectorId and source.");
}
var now = timeProvider.GetUtcNow();
var record = new OrchestratorRegistryRecord(
tenant,
request.ConnectorId.Trim(),
request.Source.Trim(),
request.Capabilities,
request.AuthRef,
new OrchestratorSchedule(
request.Schedule.Cron,
string.IsNullOrWhiteSpace(request.Schedule.TimeZone) ? "UTC" : request.Schedule.TimeZone,
request.Schedule.MaxParallelRuns,
request.Schedule.MaxLagMinutes),
new OrchestratorRatePolicy(request.RatePolicy.Rpm, request.RatePolicy.Burst, request.RatePolicy.CooldownSeconds),
request.ArtifactKinds,
request.LockKey,
new OrchestratorEgressGuard(request.EgressGuard.Allowlist, request.EgressGuard.AirgapMode),
now,
now);
await store.UpsertAsync(record, cancellationToken).ConfigureAwait(false);
return Results.Accepted();
}).WithName("UpsertOrchestratorRegistry");
orchestratorGroup.MapPost("/heartbeat", async (
HttpContext context,
[FromBody] OrchestratorHeartbeatRequest request,
[FromServices] IOrchestratorRegistryStore store,
TimeProvider timeProvider,
CancellationToken cancellationToken) =>
{
if (!TryResolveTenant(context, requireHeader: true, out var tenant, out var tenantError))
{
return tenantError;
}
if (string.IsNullOrWhiteSpace(request.ConnectorId))
{
return Problem(context, "connectorId is required", StatusCodes.Status400BadRequest, ProblemTypes.Validation, "Provide connectorId.");
}
if (request.Sequence < 0)
{
return Problem(context, "sequence must be non-negative", StatusCodes.Status400BadRequest, ProblemTypes.Validation, "Provide a non-negative sequence.");
}
var timestamp = request.TimestampUtc ?? timeProvider.GetUtcNow();
var heartbeat = new OrchestratorHeartbeatRecord(
tenant,
request.ConnectorId.Trim(),
request.RunId,
request.Sequence,
request.Status,
request.Progress,
request.QueueDepth,
request.LastArtifactHash,
request.LastArtifactKind,
request.ErrorCode,
request.RetryAfterSeconds,
timestamp);
await store.AppendHeartbeatAsync(heartbeat, cancellationToken).ConfigureAwait(false);
return Results.Accepted();
}).WithName("RecordOrchestratorHeartbeat");
orchestratorGroup.MapPost("/commands", async (
HttpContext context,
[FromBody] OrchestratorCommandRequest request,
[FromServices] IOrchestratorRegistryStore store,
CancellationToken cancellationToken) =>
{
if (!TryResolveTenant(context, requireHeader: true, out var tenant, out var tenantError))
{
return tenantError;
}
if (string.IsNullOrWhiteSpace(request.ConnectorId))
{
return Problem(context, "connectorId is required", StatusCodes.Status400BadRequest, ProblemTypes.Validation, "Provide connectorId.");
}
if (request.Sequence < 0)
{
return Problem(context, "sequence must be non-negative", StatusCodes.Status400BadRequest, ProblemTypes.Validation, "Provide a non-negative sequence.");
}
var command = new OrchestratorCommandRecord(
tenant,
request.ConnectorId.Trim(),
request.RunId,
request.Sequence,
request.Command,
request.Throttle is null
? null
: new OrchestratorThrottleOverride(
request.Throttle.Rpm,
request.Throttle.Burst,
request.Throttle.CooldownSeconds,
request.Throttle.ExpiresAt),
request.Backfill is null
? null
: new OrchestratorBackfillRange(request.Backfill.FromCursor, request.Backfill.ToCursor),
DateTimeOffset.UtcNow,
request.ExpiresAt);
await store.EnqueueCommandAsync(command, cancellationToken).ConfigureAwait(false);
return Results.Accepted();
}).WithName("EnqueueOrchestratorCommand");
orchestratorGroup.MapGet("/commands", async (
HttpContext context,
[FromQuery] string connectorId,
[FromQuery] Guid runId,
[FromQuery] long? afterSequence,
[FromServices] IOrchestratorRegistryStore store,
CancellationToken cancellationToken) =>
{
ApplyNoCache(context.Response);
if (!TryResolveTenant(context, requireHeader: true, out var tenant, out var tenantError))
{
return tenantError;
}
if (string.IsNullOrWhiteSpace(connectorId))
{
return Problem(context, "connectorId is required", StatusCodes.Status400BadRequest, ProblemTypes.Validation, "Provide connectorId.");
}
var commands = await store.GetPendingCommandsAsync(tenant, connectorId.Trim(), runId, afterSequence, cancellationToken).ConfigureAwait(false);
return Results.Ok(commands);
}).WithName("GetOrchestratorCommands");
var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web);
jsonOptions.Converters.Add(new JsonStringEnumConverter());
@@ -836,6 +993,7 @@ var advisoryEvidenceEndpoint = app.MapGet("/vuln/evidence/advisories/{advisoryKe
HttpContext context,
[FromServices] IAdvisoryRawService rawService,
[FromServices] EvidenceBundleAttestationBuilder attestationBuilder,
[FromServices] ILogger<Program> logger,
CancellationToken cancellationToken) =>
{
ApplyNoCache(context.Response);
@@ -879,10 +1037,16 @@ var advisoryEvidenceEndpoint = app.MapGet("/vuln/evidence/advisories/{advisoryKe
record.Document))
.ToArray();
var evidenceOptions = resolvedConcelierOptions.Evidence ?? new ConcelierOptions.EvidenceBundleOptions();
var attestation = await TryBuildAttestationAsync(
context,
evidenceOptions,
attestationBuilder,
logger,
cancellationToken).ConfigureAwait(false);
var responseKey = recordResponses[0].Document.AdvisoryKey ?? canonicalKey;
var response = new AdvisoryEvidenceResponse(responseKey, recordResponses);
// TODO: Attach attestation metadata when Evidence Bundle tarball is available per tenant/advisory.
// The builder is registered for future use once bundle paths are discoverable from evidence storage.
var response = new AdvisoryEvidenceResponse(responseKey, recordResponses, attestation);
return JsonResult(response);
});
if (authorityConfigured)
@@ -1622,6 +1786,120 @@ static KeyValuePair<string, object?>[] BuildJobMetricTags(string jobKind, string
new KeyValuePair<string, object?>("job.outcome", outcome),
};
static async Task<AttestationClaims?> TryBuildAttestationAsync(
HttpContext context,
ConcelierOptions.EvidenceBundleOptions evidenceOptions,
EvidenceBundleAttestationBuilder builder,
ILogger logger,
CancellationToken cancellationToken)
{
var bundlePath = context.Request.Query.TryGetValue("bundlePath", out var bundleValues)
? bundleValues.FirstOrDefault()
: null;
if (string.IsNullOrWhiteSpace(bundlePath))
{
return null;
}
var manifestPath = context.Request.Query.TryGetValue("manifestPath", out var manifestValues)
? manifestValues.FirstOrDefault()
: null;
var transparencyPath = context.Request.Query.TryGetValue("transparencyPath", out var transparencyValues)
? transparencyValues.FirstOrDefault()
: null;
var pipelineVersion = context.Request.Query.TryGetValue("pipelineVersion", out var pipelineValues)
? pipelineValues.FirstOrDefault()
: null;
pipelineVersion = string.IsNullOrWhiteSpace(pipelineVersion)
? evidenceOptions.PipelineVersion
: pipelineVersion.Trim();
var root = evidenceOptions.RootAbsolute;
var resolvedBundlePath = ResolveEvidencePath(bundlePath, root);
if (string.IsNullOrWhiteSpace(resolvedBundlePath) || !File.Exists(resolvedBundlePath))
{
return null;
}
var resolvedManifestPath = string.IsNullOrWhiteSpace(manifestPath)
? ResolveSibling(resolvedBundlePath, evidenceOptions.DefaultManifestFileName)
: ResolveEvidencePath(manifestPath!, root);
if (string.IsNullOrWhiteSpace(resolvedManifestPath) || !File.Exists(resolvedManifestPath))
{
return null;
}
var resolvedTransparencyPath = string.IsNullOrWhiteSpace(transparencyPath)
? ResolveSibling(resolvedBundlePath, evidenceOptions.DefaultTransparencyFileName)
: ResolveEvidencePath(transparencyPath!, root);
try
{
return await builder.BuildAsync(
new EvidenceBundleAttestationRequest(
resolvedBundlePath!,
resolvedManifestPath!,
resolvedTransparencyPath,
pipelineVersion ?? "git:unknown"),
cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
logger.LogWarning(ex, "Failed to build attestation for evidence bundle {BundlePath}", resolvedBundlePath);
return null;
}
}
static string? ResolveEvidencePath(string candidate, string root)
{
if (string.IsNullOrWhiteSpace(candidate))
{
return null;
}
var path = candidate;
if (!Path.IsPathRooted(path))
{
path = Path.Combine(root, path);
}
var fullPath = Path.GetFullPath(path);
if (!string.IsNullOrWhiteSpace(root))
{
var rootPath = Path.GetFullPath(root)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
if (!fullPath.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase))
{
return null;
}
}
return fullPath;
}
static string? ResolveSibling(string? bundlePath, string? fileName)
{
if (string.IsNullOrWhiteSpace(bundlePath) || string.IsNullOrWhiteSpace(fileName))
{
return null;
}
var directory = Path.GetDirectoryName(bundlePath);
if (string.IsNullOrWhiteSpace(directory))
{
return null;
}
return Path.Combine(directory, fileName);
}
void ApplyNoCache(HttpResponse response)
{
if (response is null)

View File

@@ -39,7 +39,8 @@ public sealed record AdvisoryLinksetProvenance(
public sealed record AdvisoryLinksetConflict(
string Field,
string Reason,
IReadOnlyList<string>? Values);
IReadOnlyList<string>? Values,
IReadOnlyList<string>? SourceIds = null);
internal static class BsonDocumentHelper
{

View File

@@ -32,10 +32,23 @@ internal static class AdvisoryLinksetNormalization
ArgumentNullException.ThrowIfNull(linkset);
var normalized = Build(linkset.PackageUrls);
var conflicts = ExtractConflicts(linkset);
var confidence = ComputeConfidence(linkset, providedConfidence, conflicts);
return (normalized, confidence, conflicts);
var inputs = new[]
{
new LinksetCorrelation.Input(
Vendor: null,
FetchedAt: null,
Aliases: linkset.Aliases,
Purls: linkset.PackageUrls,
Cpes: linkset.Cpes,
References: linkset.References.Select(r => r.Url).ToArray())
};
var noteConflicts = ExtractConflicts(linkset);
var (confidenceScore, conflicts) = LinksetCorrelation.Compute(inputs, noteConflicts);
var coerced = providedConfidence.HasValue ? CoerceConfidence(providedConfidence) : confidenceScore;
return (normalized, coerced, conflicts);
}
private static AdvisoryLinksetNormalized? Build(IEnumerable<string> purlValues)
@@ -190,37 +203,4 @@ internal static class AdvisoryLinksetNormalization
return conflicts;
}
private static double? ComputeConfidence(RawLinkset linkset, double? providedConfidence, IReadOnlyList<AdvisoryLinksetConflict> conflicts)
{
if (providedConfidence.HasValue)
{
return CoerceConfidence(providedConfidence);
}
double aliasScore = linkset.Aliases.IsDefaultOrEmpty ? 0d : 1d;
double purlOverlapScore = linkset.PackageUrls.IsDefaultOrEmpty
? 0d
: (linkset.PackageUrls.Length > 1 ? 1d : 0.6d);
double cpeOverlapScore = linkset.Cpes.IsDefaultOrEmpty
? 0d
: (linkset.Cpes.Length > 1 ? 1d : 0.5d);
double severityAgreement = conflicts.Any(c => c.Reason == "severity-mismatch") ? 0.2d : 0.5d;
double referenceOverlap = linkset.References.IsDefaultOrEmpty ? 0d : 0.5d;
double freshnessScore = 0.5d; // until fetchedAt spread is available
var confidence = (0.40 * aliasScore) +
(0.25 * purlOverlapScore) +
(0.15 * cpeOverlapScore) +
(0.10 * severityAgreement) +
(0.05 * referenceOverlap) +
(0.05 * freshnessScore);
if (conflicts.Count > 0 && confidence > 0.7d)
{
confidence -= 0.1d; // penalize non-empty conflict sets
}
return Math.Clamp(confidence, 0d, 1d);
}
}

View File

@@ -0,0 +1,346 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using StellaOps.Concelier.Models;
namespace StellaOps.Concelier.Core.Linksets;
internal static class LinksetCorrelation
{
internal readonly record struct Input(
string? Vendor,
DateTimeOffset? FetchedAt,
IReadOnlyCollection<string> Aliases,
IReadOnlyCollection<string> Purls,
IReadOnlyCollection<string> Cpes,
IReadOnlyCollection<string> References);
internal static (double Confidence, IReadOnlyList<AdvisoryLinksetConflict> Conflicts) Compute(
IReadOnlyCollection<Input> inputs,
IReadOnlyList<AdvisoryLinksetConflict>? additionalConflicts = null)
{
if (inputs.Count == 0)
{
return (1.0, Array.Empty<AdvisoryLinksetConflict>());
}
var conflicts = new List<AdvisoryLinksetConflict>();
var aliasScore = CalculateAliasScore(inputs, conflicts);
var (purlScore, rangeConflicts) = CalculatePurlScore(inputs);
conflicts.AddRange(rangeConflicts);
var cpeScore = CalculateCpeScore(inputs);
var (referenceScore, referenceConflicts) = CalculateReferenceScore(inputs);
conflicts.AddRange(referenceConflicts);
var severityAgreement = 0.5d; // no severity data available in linkset inputs
var freshnessScore = CalculateFreshnessScore(inputs);
var baseConfidence = Clamp01(
(0.40d * aliasScore) +
(0.25d * purlScore) +
(0.15d * cpeScore) +
(0.10d * severityAgreement) +
(0.05d * referenceScore) +
(0.05d * freshnessScore));
if (conflicts.Count > 0 && baseConfidence > 0.7d)
{
baseConfidence -= 0.1d;
}
if (baseConfidence < 0.1d && conflicts.Count > 0)
{
baseConfidence = 0.1d; // keep deterministic low signal, not zero
}
if (additionalConflicts is { Count: > 0 })
{
conflicts.AddRange(additionalConflicts);
}
return (Clamp01(baseConfidence), DeduplicateAndSort(conflicts, inputs));
}
private static double CalculateAliasScore(IReadOnlyCollection<Input> inputs, List<AdvisoryLinksetConflict> conflicts)
{
if (inputs.Count == 1)
{
return inputs.First().Aliases.Count > 0 ? 1d : 0d;
}
var intersection = inputs
.Select(i => i.Aliases.Select(a => a.ToLowerInvariant()).ToHashSet(StringComparer.Ordinal))
.Aggregate((acc, next) =>
{
acc.IntersectWith(next);
return acc;
});
if (intersection.Count > 0)
{
return 1d;
}
var anyAliases = inputs.Any(i => i.Aliases.Count > 0);
if (anyAliases)
{
var values = inputs
.Select(i => $"{i.Vendor ?? "source"}:{i.Aliases.FirstOrDefault() ?? "<none>"}")
.ToArray();
conflicts.Add(new AdvisoryLinksetConflict("aliases", "alias-inconsistency", values));
}
var vendors = inputs.Select(i => i.Vendor ?? string.Empty).ToHashSet(StringComparer.OrdinalIgnoreCase);
return vendors.Count == 1 ? 0.5d : 0d;
}
private static (double Score, IReadOnlyList<AdvisoryLinksetConflict> Conflicts) CalculatePurlScore(
IReadOnlyCollection<Input> inputs)
{
var conflicts = new List<AdvisoryLinksetConflict>();
if (inputs.All(i => i.Purls.Count == 0))
{
return (0d, conflicts);
}
List<HashSet<string>> packageKeysPerInput = inputs
.Select(i => i.Purls
.Select(ExtractPackageKey)
.Where(k => !string.IsNullOrEmpty(k))
.ToHashSet(StringComparer.Ordinal))
.ToList();
var sharedPackages = packageKeysPerInput
.Skip(1)
.Aggregate(
new HashSet<string>(packageKeysPerInput.First()!, StringComparer.Ordinal),
(acc, next) =>
{
acc.IntersectWith(next!);
return acc;
});
if (sharedPackages.Count > 0)
{
var hasExactPurlOverlap = HasExactPurlOverlap(inputs);
if (!hasExactPurlOverlap)
{
var divergent = CollectRangeConflicts(inputs, sharedPackages);
conflicts.AddRange(divergent);
}
return (hasExactPurlOverlap ? 1d : 0.6d, conflicts);
}
return (0d, conflicts);
}
private static IEnumerable<AdvisoryLinksetConflict> CollectRangeConflicts(
IReadOnlyCollection<Input> inputs,
HashSet<string> sharedPackages)
{
var conflicts = new List<AdvisoryLinksetConflict>();
foreach (var package in sharedPackages)
{
var values = inputs
.SelectMany(i => i.Purls
.Where(p => ExtractPackageKey(p) == package)
.Select(p => $"{i.Vendor ?? "source"}:{p}"))
.ToArray();
var sourceIds = inputs
.Select(i => i.Vendor ?? "source")
.ToArray();
if (values.Length > 1)
{
conflicts.Add(new AdvisoryLinksetConflict(
"affected.versions",
"affected-range-divergence",
values,
sourceIds));
}
}
return conflicts;
}
private static bool HasExactPurlOverlap(IReadOnlyCollection<Input> inputs)
{
var first = inputs.First().Purls.ToHashSet(StringComparer.Ordinal);
return inputs.Skip(1).Any(input => input.Purls.Any(first.Contains));
}
private static string ExtractPackageKey(string purl)
{
if (string.IsNullOrWhiteSpace(purl))
{
return string.Empty;
}
var atIndex = purl.LastIndexOf('@');
return atIndex > 0 ? purl[..atIndex] : purl;
}
private static double CalculateCpeScore(IReadOnlyCollection<Input> inputs)
{
if (inputs.All(i => i.Cpes.Count == 0))
{
return 0d;
}
var cpeSets = inputs.Select(i => i.Cpes.ToHashSet(StringComparer.OrdinalIgnoreCase)).ToList();
var exactOverlap = cpeSets.Skip(1).Any(set => set.Overlaps(cpeSets.First()));
if (exactOverlap)
{
return 1d;
}
var vendorProductSets = inputs
.Select(i => i.Cpes.Select(ParseVendorProduct).Where(vp => vp.vendor is not null).ToHashSet())
.ToList();
var sharedVendorProduct = vendorProductSets.Skip(1).Any(set => set.Overlaps(vendorProductSets.First()));
return sharedVendorProduct ? 0.5d : 0d;
}
private static (string? vendor, string? product) ParseVendorProduct(string cpe)
{
if (string.IsNullOrWhiteSpace(cpe))
{
return (null, null);
}
var parts = cpe.Split(':');
if (parts.Length >= 6 && parts[0].StartsWith("cpe", StringComparison.OrdinalIgnoreCase))
{
// cpe:2.3:a:vendor:product:version...
return (parts[3], parts[4]);
}
if (parts.Length >= 5 && parts[0] == "cpe" && parts[1] == "/")
{
return (parts[2], parts[3]);
}
return (null, null);
}
private static (double Score, IReadOnlyList<AdvisoryLinksetConflict> Conflicts) CalculateReferenceScore(
IReadOnlyCollection<Input> inputs)
{
var conflicts = new List<AdvisoryLinksetConflict>();
if (inputs.All(i => i.References.Count == 0))
{
return (0d, conflicts);
}
double maxOverlap = 0d;
var inputList = inputs.ToList();
for (var i = 0; i < inputList.Count; i++)
{
for (var j = i + 1; j < inputList.Count; j++)
{
var first = inputList[i].References.Select(r => r.ToLowerInvariant()).ToHashSet();
var second = inputList[j].References.Select(r => r.ToLowerInvariant()).ToHashSet();
var intersection = first.Intersect(second).Count();
var denom = Math.Max(first.Count, second.Count);
var overlap = denom == 0 ? 0d : (double)intersection / denom;
if (overlap > maxOverlap)
{
maxOverlap = overlap;
}
if (overlap == 0d && !string.Equals(inputList[i].Vendor, inputList[j].Vendor, StringComparison.OrdinalIgnoreCase))
{
var values = new[]
{
$"{inputList[i].Vendor ?? "source"}:{first.FirstOrDefault() ?? "<none>"}",
$"{inputList[j].Vendor ?? "source"}:{second.FirstOrDefault() ?? "<none>"}"
};
conflicts.Add(new AdvisoryLinksetConflict(
"references",
"reference-clash",
values,
new[]
{
inputList[i].Vendor ?? "source",
inputList[j].Vendor ?? "source"
}));
}
}
}
return (maxOverlap, conflicts);
}
private static double CalculateFreshnessScore(IReadOnlyCollection<Input> inputs)
{
var fetched = inputs
.Select(i => i.FetchedAt)
.Where(d => d.HasValue)
.Select(d => d!.Value)
.ToList();
if (fetched.Count <= 1)
{
return 0.5d; // neutral when unknown
}
var min = fetched.Min();
var max = fetched.Max();
var spread = max - min;
if (spread <= TimeSpan.FromHours(48))
{
return 1d;
}
if (spread >= TimeSpan.FromDays(14))
{
return 0d;
}
var remaining = TimeSpan.FromDays(14) - spread;
return Clamp01(remaining.TotalSeconds / TimeSpan.FromDays(14).TotalSeconds);
}
private static IReadOnlyList<AdvisoryLinksetConflict> DeduplicateAndSort(
IEnumerable<AdvisoryLinksetConflict> conflicts,
IReadOnlyCollection<Input> inputs)
{
var set = new HashSet<string>(StringComparer.Ordinal);
var list = new List<AdvisoryLinksetConflict>();
foreach (var conflict in conflicts)
{
var key = $"{conflict.Field}|{conflict.Reason}|{string.Join('|', conflict.Values ?? Array.Empty<string>())}";
if (set.Add(key))
{
if (conflict.SourceIds is null || conflict.SourceIds.Count == 0)
{
var allSources = inputs.Select(i => i.Vendor ?? "source").Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
list.Add(conflict with { SourceIds = allSources });
}
else
{
list.Add(conflict);
}
}
}
return list
.OrderBy(c => c.Field, StringComparer.Ordinal)
.ThenBy(c => c.Reason, StringComparer.Ordinal)
.ThenBy(c => string.Join('|', c.Values ?? Array.Empty<string>()), StringComparer.Ordinal)
.ToList();
}
private static double Clamp01(double value) => Math.Clamp(value, 0d, 1d);
}

View File

@@ -216,9 +216,8 @@ public sealed class AdvisoryObservationQueryService : IAdvisoryObservationQueryS
var referenceSet = new HashSet<AdvisoryObservationReference>();
var scopeSet = new HashSet<string>(StringComparer.Ordinal);
var relationshipSet = new HashSet<RawRelationship>();
var conflictSet = new HashSet<string>(StringComparer.Ordinal);
var conflicts = new List<AdvisoryLinksetConflict>();
var confidence = 1.0;
var correlationInputs = new List<LinksetCorrelation.Input>(observations.Length);
foreach (var observation in observations)
{
@@ -252,19 +251,17 @@ public sealed class AdvisoryObservationQueryService : IAdvisoryObservationQueryS
relationshipSet.Add(relationship);
}
var linksetProjection = AdvisoryLinksetNormalization.FromRawLinksetWithConfidence(observation.RawLinkset);
confidence = Math.Min(confidence, linksetProjection.confidence ?? 1.0);
foreach (var conflict in linksetProjection.conflicts)
{
var key = $"{conflict.Field}|{conflict.Reason}|{string.Join('|', conflict.Values ?? Array.Empty<string>())}";
if (conflictSet.Add(key))
{
conflicts.Add(conflict);
}
}
correlationInputs.Add(new LinksetCorrelation.Input(
observation.Source.Vendor,
observation.Upstream.FetchedAt,
observation.Linkset.Aliases,
observation.Linkset.Purls,
observation.Linkset.Cpes,
observation.Linkset.References.Select(r => r.Url).ToArray()));
}
var (confidence, conflicts) = LinksetCorrelation.Compute(correlationInputs);
return new AdvisoryObservationLinksetAggregate(
aliasSet.OrderBy(static alias => alias, StringComparer.Ordinal).ToImmutableArray(),
purlSet.OrderBy(static purl => purl, StringComparer.Ordinal).ToImmutableArray(),

View File

@@ -0,0 +1,12 @@
using System.Threading;
using System.Threading.Tasks;
namespace StellaOps.Concelier.Core.Observations;
/// <summary>
/// Transports advisory.observation.updated@1 events from the outbox to external subscribers (e.g., NATS).
/// </summary>
public interface IAdvisoryObservationEventTransport
{
Task SendAsync(AdvisoryObservationUpdatedEvent @event, CancellationToken cancellationToken);
}

View File

@@ -108,5 +108,10 @@ public sealed class AdvisoryLinksetConflictDocument
[BsonElement("values")]
[BsonIgnoreIfNull]
public List<string>? Values { get; set; }
= null;
= new();
[BsonElement("sourceIds")]
[BsonIgnoreIfNull]
public List<string>? SourceIds { get; set; }
= new();
}

View File

@@ -111,7 +111,8 @@ internal sealed class ConcelierMongoLinksetStore : IMongoAdvisoryLinksetStore
{
Field = conflict.Field,
Reason = conflict.Reason,
Values = conflict.Values is null ? null : new List<string>(conflict.Values)
Values = conflict.Values is null ? null : new List<string>(conflict.Values),
SourceIds = conflict.SourceIds is null ? null : new List<string>(conflict.SourceIds)
}).ToList(),
Provenance = linkset.Provenance is null ? null : new AdvisoryLinksetProvenanceDocument
{
@@ -153,7 +154,8 @@ internal sealed class ConcelierMongoLinksetStore : IMongoAdvisoryLinksetStore
: doc.Conflicts.Select(conflict => new CoreLinksets.AdvisoryLinksetConflict(
conflict.Field,
conflict.Reason,
conflict.Values)).ToList(),
conflict.Values,
conflict.SourceIds)).ToList(),
DateTime.SpecifyKind(doc.CreatedAt, DateTimeKind.Utc),
doc.BuiltByJobId);
}

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using MongoDB.Bson;
using MongoDB.Driver;
using StellaOps.Concelier.Storage.Mongo.Orchestrator;
namespace StellaOps.Concelier.Storage.Mongo.Migrations;
internal sealed class EnsureOrchestratorCollectionsMigration : IMongoMigration
{
public string Id => "20251122_orchestrator_registry_commands";
public string Description => "Ensure orchestrator registry, commands, and heartbeats collections exist with indexes";
public async Task ApplyAsync(IMongoDatabase database, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(database);
await EnsureRegistryAsync(database, cancellationToken).ConfigureAwait(false);
await EnsureCommandsAsync(database, cancellationToken).ConfigureAwait(false);
await EnsureHeartbeatsAsync(database, cancellationToken).ConfigureAwait(false);
}
private static async Task EnsureRegistryAsync(IMongoDatabase database, CancellationToken ct)
{
var name = MongoStorageDefaults.Collections.OrchestratorRegistry;
await EnsureCollectionAsync(database, name, ct).ConfigureAwait(false);
var collection = database.GetCollection<BsonDocument>(name);
var indexes = new List<CreateIndexModel<BsonDocument>>
{
new(new BsonDocument
{
{"tenant", 1},
{"connectorId", 1},
}, new CreateIndexOptions { Name = "orch_registry_tenant_connector", Unique = true }),
new(new BsonDocument
{
{"source", 1},
}, new CreateIndexOptions { Name = "orch_registry_source" }),
};
await collection.Indexes.CreateManyAsync(indexes, cancellationToken: ct).ConfigureAwait(false);
}
private static async Task EnsureCommandsAsync(IMongoDatabase database, CancellationToken ct)
{
var name = MongoStorageDefaults.Collections.OrchestratorCommands;
await EnsureCollectionAsync(database, name, ct).ConfigureAwait(false);
var collection = database.GetCollection<BsonDocument>(name);
var indexes = new List<CreateIndexModel<BsonDocument>>
{
new(new BsonDocument
{
{"tenant", 1},
{"connectorId", 1},
{"runId", 1},
{"sequence", 1},
}, new CreateIndexOptions { Name = "orch_cmd_tenant_connector_run_seq" }),
new(new BsonDocument { {"expiresAt", 1} }, new CreateIndexOptions
{
Name = "orch_cmd_expiresAt_ttl",
ExpireAfter = TimeSpan.FromSeconds(0),
})
};
await collection.Indexes.CreateManyAsync(indexes, cancellationToken: ct).ConfigureAwait(false);
}
private static async Task EnsureHeartbeatsAsync(IMongoDatabase database, CancellationToken ct)
{
var name = MongoStorageDefaults.Collections.OrchestratorHeartbeats;
await EnsureCollectionAsync(database, name, ct).ConfigureAwait(false);
var collection = database.GetCollection<BsonDocument>(name);
var indexes = new List<CreateIndexModel<BsonDocument>>
{
new(new BsonDocument
{
{"tenant", 1},
{"connectorId", 1},
{"runId", 1},
{"sequence", 1},
}, new CreateIndexOptions { Name = "orch_hb_tenant_connector_run_seq" }),
new(new BsonDocument { {"timestamp", -1} }, new CreateIndexOptions { Name = "orch_hb_timestamp_desc" })
};
await collection.Indexes.CreateManyAsync(indexes, cancellationToken: ct).ConfigureAwait(false);
}
private static async Task EnsureCollectionAsync(IMongoDatabase database, string collectionName, CancellationToken ct)
{
var filter = new BsonDocument("name", collectionName);
using var cursor = await database.ListCollectionsAsync(new ListCollectionsOptions { Filter = filter }, ct).ConfigureAwait(false);
var exists = await cursor.AnyAsync(ct).ConfigureAwait(false);
if (!exists)
{
await database.CreateCollectionAsync(collectionName, cancellationToken: ct).ConfigureAwait(false);
}
}
}

View File

@@ -30,5 +30,8 @@ public static class MongoStorageDefaults
public const string AdvisoryObservations = "advisory_observations";
public const string AdvisoryLinksets = "advisory_linksets";
public const string AdvisoryObservationEvents = "advisory_observation_events";
public const string OrchestratorRegistry = "orchestrator_registry";
public const string OrchestratorCommands = "orchestrator_commands";
public const string OrchestratorHeartbeats = "orchestrator_heartbeats";
}
}

View File

@@ -11,18 +11,18 @@ namespace StellaOps.Concelier.Storage.Mongo.Observations;
internal sealed class AdvisoryObservationTransportWorker : BackgroundService
{
private readonly IAdvisoryObservationEventOutbox _outbox;
private readonly IAdvisoryObservationEventPublisher _publisher;
private readonly IAdvisoryObservationEventTransport _transport;
private readonly ILogger<AdvisoryObservationTransportWorker> _logger;
private readonly AdvisoryObservationEventPublisherOptions _options;
public AdvisoryObservationTransportWorker(
IAdvisoryObservationEventOutbox outbox,
IAdvisoryObservationEventPublisher publisher,
IAdvisoryObservationEventTransport transport,
IOptions<AdvisoryObservationEventPublisherOptions> options,
ILogger<AdvisoryObservationTransportWorker> logger)
{
_outbox = outbox ?? throw new ArgumentNullException(nameof(outbox));
_publisher = publisher ?? throw new ArgumentNullException(nameof(publisher));
_transport = transport ?? throw new ArgumentNullException(nameof(transport));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_options = options.Value;
}
@@ -48,7 +48,7 @@ internal sealed class AdvisoryObservationTransportWorker : BackgroundService
foreach (var evt in batch)
{
await _publisher.PublishAsync(evt, stoppingToken).ConfigureAwait(false);
await _transport.SendAsync(evt, stoppingToken).ConfigureAwait(false);
await _outbox.MarkPublishedAsync(evt.EventId, DateTimeOffset.UtcNow, stoppingToken).ConfigureAwait(false);
}
}

View File

@@ -12,7 +12,7 @@ using StellaOps.Concelier.Core.Observations;
namespace StellaOps.Concelier.Storage.Mongo.Observations;
internal sealed class NatsAdvisoryObservationEventPublisher : IAdvisoryObservationEventPublisher
internal sealed class NatsAdvisoryObservationEventPublisher : IAdvisoryObservationEventTransport
{
private readonly ILogger<NatsAdvisoryObservationEventPublisher> _logger;
private readonly AdvisoryObservationEventPublisherOptions _options;
@@ -26,7 +26,7 @@ internal sealed class NatsAdvisoryObservationEventPublisher : IAdvisoryObservati
_options = options.Value;
}
public async Task PublishAsync(AdvisoryObservationUpdatedEvent @event, CancellationToken cancellationToken)
public async Task SendAsync(AdvisoryObservationUpdatedEvent @event, CancellationToken cancellationToken)
{
if (!_options.Enabled)
{

View File

@@ -0,0 +1,15 @@
using System.Threading;
using System.Threading.Tasks;
using StellaOps.Concelier.Core.Observations;
namespace StellaOps.Concelier.Storage.Mongo.Observations;
internal sealed class NullAdvisoryObservationEventTransport : IAdvisoryObservationEventTransport
{
public static readonly NullAdvisoryObservationEventTransport Instance = new();
private NullAdvisoryObservationEventTransport() { }
public Task SendAsync(AdvisoryObservationUpdatedEvent @event, CancellationToken cancellationToken)
=> Task.CompletedTask;
}

View File

@@ -0,0 +1,19 @@
namespace StellaOps.Concelier.Storage.Mongo.Orchestrator;
public interface IOrchestratorRegistryStore
{
Task UpsertAsync(OrchestratorRegistryRecord record, CancellationToken cancellationToken);
Task<OrchestratorRegistryRecord?> GetAsync(string tenant, string connectorId, CancellationToken cancellationToken);
Task EnqueueCommandAsync(OrchestratorCommandRecord command, CancellationToken cancellationToken);
Task<IReadOnlyList<OrchestratorCommandRecord>> GetPendingCommandsAsync(
string tenant,
string connectorId,
Guid runId,
long? afterSequence,
CancellationToken cancellationToken);
Task AppendHeartbeatAsync(OrchestratorHeartbeatRecord heartbeat, CancellationToken cancellationToken);
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Linq;
using MongoDB.Driver;
namespace StellaOps.Concelier.Storage.Mongo.Orchestrator;
public sealed class MongoOrchestratorRegistryStore : IOrchestratorRegistryStore
{
private readonly IMongoCollection<OrchestratorRegistryDocument> _registry;
private readonly IMongoCollection<OrchestratorCommandDocument> _commands;
private readonly IMongoCollection<OrchestratorHeartbeatDocument> _heartbeats;
public MongoOrchestratorRegistryStore(
IMongoCollection<OrchestratorRegistryDocument> registry,
IMongoCollection<OrchestratorCommandDocument> commands,
IMongoCollection<OrchestratorHeartbeatDocument> heartbeats)
{
_registry = registry ?? throw new ArgumentNullException(nameof(registry));
_commands = commands ?? throw new ArgumentNullException(nameof(commands));
_heartbeats = heartbeats ?? throw new ArgumentNullException(nameof(heartbeats));
}
public async Task UpsertAsync(OrchestratorRegistryRecord record, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(record);
var document = OrchestratorRegistryDocumentExtensions.FromRecord(record);
var filter = Builders<OrchestratorRegistryDocument>.Filter.And(
Builders<OrchestratorRegistryDocument>.Filter.Eq(x => x.Tenant, record.Tenant),
Builders<OrchestratorRegistryDocument>.Filter.Eq(x => x.ConnectorId, record.ConnectorId));
var options = new ReplaceOptions { IsUpsert = true };
await _registry.ReplaceOneAsync(filter, document, options, cancellationToken).ConfigureAwait(false);
}
public async Task<OrchestratorRegistryRecord?> GetAsync(string tenant, string connectorId, CancellationToken cancellationToken)
{
var filter = Builders<OrchestratorRegistryDocument>.Filter.And(
Builders<OrchestratorRegistryDocument>.Filter.Eq(x => x.Tenant, tenant),
Builders<OrchestratorRegistryDocument>.Filter.Eq(x => x.ConnectorId, connectorId));
var document = await _registry
.Find(filter)
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
return document?.ToRecord();
}
public async Task EnqueueCommandAsync(OrchestratorCommandRecord command, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(command);
var document = OrchestratorCommandDocumentExtensions.FromRecord(command);
await _commands.InsertOneAsync(document, cancellationToken: cancellationToken).ConfigureAwait(false);
}
public async Task<IReadOnlyList<OrchestratorCommandRecord>> GetPendingCommandsAsync(
string tenant,
string connectorId,
Guid runId,
long? afterSequence,
CancellationToken cancellationToken)
{
var filter = Builders<OrchestratorCommandDocument>.Filter.And(
Builders<OrchestratorCommandDocument>.Filter.Eq(x => x.Tenant, tenant),
Builders<OrchestratorCommandDocument>.Filter.Eq(x => x.ConnectorId, connectorId),
Builders<OrchestratorCommandDocument>.Filter.Eq(x => x.RunId, runId));
if (afterSequence.HasValue)
{
filter &= Builders<OrchestratorCommandDocument>.Filter.Gt(x => x.Sequence, afterSequence.Value);
}
var results = await _commands
.Find(filter)
.Sort(Builders<OrchestratorCommandDocument>.Sort.Ascending(x => x.Sequence))
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
return results
.Select(static c => c.ToRecord())
.ToArray();
}
public async Task AppendHeartbeatAsync(OrchestratorHeartbeatRecord heartbeat, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(heartbeat);
var document = OrchestratorHeartbeatDocumentExtensions.FromRecord(heartbeat);
await _heartbeats.InsertOneAsync(document, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,141 @@
using System;
using System.Globalization;
using MongoDB.Bson.Serialization.Attributes;
namespace StellaOps.Concelier.Storage.Mongo.Orchestrator;
[BsonIgnoreExtraElements]
public sealed class OrchestratorCommandDocument
{
[BsonId]
public string Id { get; set; } = string.Empty;
[BsonElement("tenant")]
public string Tenant { get; set; } = string.Empty;
[BsonElement("connectorId")]
public string ConnectorId { get; set; } = string.Empty;
[BsonElement("runId")]
public Guid RunId { get; set; }
= Guid.Empty;
[BsonElement("sequence")]
public long Sequence { get; set; }
= 0;
[BsonElement("command")]
public OrchestratorCommandKind Command { get; set; }
= OrchestratorCommandKind.Pause;
[BsonElement("throttle")]
public OrchestratorThrottleOverrideDocument? Throttle { get; set; }
= null;
[BsonElement("backfill")]
public OrchestratorBackfillRangeDocument? Backfill { get; set; }
= null;
[BsonElement("createdAt")]
public DateTime CreatedAt { get; set; }
= DateTime.SpecifyKind(DateTime.UnixEpoch, DateTimeKind.Utc);
[BsonElement("expiresAt")]
public DateTime? ExpiresAt { get; set; }
= null;
}
[BsonIgnoreExtraElements]
public sealed class OrchestratorThrottleOverrideDocument
{
[BsonElement("rpm")]
public int? Rpm { get; set; }
= null;
[BsonElement("burst")]
public int? Burst { get; set; }
= null;
[BsonElement("cooldownSeconds")]
public int? CooldownSeconds { get; set; }
= null;
[BsonElement("expiresAt")]
public DateTime? ExpiresAt { get; set; }
= null;
}
[BsonIgnoreExtraElements]
public sealed class OrchestratorBackfillRangeDocument
{
[BsonElement("fromCursor")]
public string? FromCursor { get; set; }
= null;
[BsonElement("toCursor")]
public string? ToCursor { get; set; }
= null;
}
internal static class OrchestratorCommandDocumentExtensions
{
public static OrchestratorCommandDocument FromRecord(OrchestratorCommandRecord record)
{
ArgumentNullException.ThrowIfNull(record);
return new OrchestratorCommandDocument
{
Id = BuildId(record.Tenant, record.ConnectorId, record.RunId, record.Sequence),
Tenant = record.Tenant,
ConnectorId = record.ConnectorId,
RunId = record.RunId,
Sequence = record.Sequence,
Command = record.Command,
Throttle = record.Throttle is null
? null
: new OrchestratorThrottleOverrideDocument
{
Rpm = record.Throttle.Rpm,
Burst = record.Throttle.Burst,
CooldownSeconds = record.Throttle.CooldownSeconds,
ExpiresAt = record.Throttle.ExpiresAt?.UtcDateTime,
},
Backfill = record.Backfill is null
? null
: new OrchestratorBackfillRangeDocument
{
FromCursor = record.Backfill.FromCursor,
ToCursor = record.Backfill.ToCursor,
},
CreatedAt = record.CreatedAt.UtcDateTime,
ExpiresAt = record.ExpiresAt?.UtcDateTime,
};
}
public static OrchestratorCommandRecord ToRecord(this OrchestratorCommandDocument document)
{
ArgumentNullException.ThrowIfNull(document);
return new OrchestratorCommandRecord(
document.Tenant,
document.ConnectorId,
document.RunId,
document.Sequence,
document.Command,
document.Throttle is null
? null
: new OrchestratorThrottleOverride(
document.Throttle.Rpm,
document.Throttle.Burst,
document.Throttle.CooldownSeconds,
document.Throttle.ExpiresAt is null ? null : DateTime.SpecifyKind(document.Throttle.ExpiresAt.Value, DateTimeKind.Utc)),
document.Backfill is null
? null
: new OrchestratorBackfillRange(document.Backfill.FromCursor, document.Backfill.ToCursor),
DateTime.SpecifyKind(document.CreatedAt, DateTimeKind.Utc),
document.ExpiresAt is null ? null : DateTime.SpecifyKind(document.ExpiresAt.Value, DateTimeKind.Utc));
}
private static string BuildId(string tenant, string connectorId, Guid runId, long sequence)
=> string.Create(CultureInfo.InvariantCulture, $"{tenant}:{connectorId}:{runId}:{sequence}");
}

View File

@@ -0,0 +1,26 @@
using System;
namespace StellaOps.Concelier.Storage.Mongo.Orchestrator;
public sealed record OrchestratorCommandRecord(
string Tenant,
string ConnectorId,
Guid RunId,
long Sequence,
OrchestratorCommandKind Command,
OrchestratorThrottleOverride? Throttle,
OrchestratorBackfillRange? Backfill,
DateTimeOffset CreatedAt,
DateTimeOffset? ExpiresAt);
public enum OrchestratorCommandKind
{
Pause,
Resume,
Throttle,
Backfill,
}
public sealed record OrchestratorThrottleOverride(int? Rpm, int? Burst, int? CooldownSeconds, DateTimeOffset? ExpiresAt);
public sealed record OrchestratorBackfillRange(string? FromCursor, string? ToCursor);

View File

@@ -0,0 +1,105 @@
using System;
using System.Globalization;
using MongoDB.Bson.Serialization.Attributes;
namespace StellaOps.Concelier.Storage.Mongo.Orchestrator;
[BsonIgnoreExtraElements]
public sealed class OrchestratorHeartbeatDocument
{
[BsonId]
public string Id { get; set; } = string.Empty;
[BsonElement("tenant")]
public string Tenant { get; set; } = string.Empty;
[BsonElement("connectorId")]
public string ConnectorId { get; set; } = string.Empty;
[BsonElement("runId")]
public Guid RunId { get; set; }
= Guid.Empty;
[BsonElement("sequence")]
public long Sequence { get; set; }
= 0;
[BsonElement("status")]
public OrchestratorHeartbeatStatus Status { get; set; }
= OrchestratorHeartbeatStatus.Starting;
[BsonElement("progress")]
public int? Progress { get; set; }
= null;
[BsonElement("queueDepth")]
public int? QueueDepth { get; set; }
= null;
[BsonElement("lastArtifactHash")]
public string? LastArtifactHash { get; set; }
= null;
[BsonElement("lastArtifactKind")]
public string? LastArtifactKind { get; set; }
= null;
[BsonElement("errorCode")]
public string? ErrorCode { get; set; }
= null;
[BsonElement("retryAfterSeconds")]
public int? RetryAfterSeconds { get; set; }
= null;
[BsonElement("timestamp")]
public DateTime Timestamp { get; set; }
= DateTime.SpecifyKind(DateTime.UnixEpoch, DateTimeKind.Utc);
}
internal static class OrchestratorHeartbeatDocumentExtensions
{
public static OrchestratorHeartbeatDocument FromRecord(OrchestratorHeartbeatRecord record)
{
ArgumentNullException.ThrowIfNull(record);
return new OrchestratorHeartbeatDocument
{
Id = BuildId(record.Tenant, record.ConnectorId, record.RunId, record.Sequence),
Tenant = record.Tenant,
ConnectorId = record.ConnectorId,
RunId = record.RunId,
Sequence = record.Sequence,
Status = record.Status,
Progress = record.Progress,
QueueDepth = record.QueueDepth,
LastArtifactHash = record.LastArtifactHash,
LastArtifactKind = record.LastArtifactKind,
ErrorCode = record.ErrorCode,
RetryAfterSeconds = record.RetryAfterSeconds,
Timestamp = record.TimestampUtc.UtcDateTime,
};
}
public static OrchestratorHeartbeatRecord ToRecord(this OrchestratorHeartbeatDocument document)
{
ArgumentNullException.ThrowIfNull(document);
return new OrchestratorHeartbeatRecord(
document.Tenant,
document.ConnectorId,
document.RunId,
document.Sequence,
document.Status,
document.Progress,
document.QueueDepth,
document.LastArtifactHash,
document.LastArtifactKind,
document.ErrorCode,
document.RetryAfterSeconds,
DateTime.SpecifyKind(document.Timestamp, DateTimeKind.Utc));
}
private static string BuildId(string tenant, string connectorId, Guid runId, long sequence)
=> string.Create(CultureInfo.InvariantCulture, $"{tenant}:{connectorId}:{runId}:{sequence}");
}

View File

@@ -0,0 +1,28 @@
using System;
namespace StellaOps.Concelier.Storage.Mongo.Orchestrator;
public sealed record OrchestratorHeartbeatRecord(
string Tenant,
string ConnectorId,
Guid RunId,
long Sequence,
OrchestratorHeartbeatStatus Status,
int? Progress,
int? QueueDepth,
string? LastArtifactHash,
string? LastArtifactKind,
string? ErrorCode,
int? RetryAfterSeconds,
DateTimeOffset TimestampUtc);
public enum OrchestratorHeartbeatStatus
{
Starting,
Running,
Paused,
Throttled,
Backfill,
Failed,
Succeeded,
}

View File

@@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using MongoDB.Bson.Serialization.Attributes;
namespace StellaOps.Concelier.Storage.Mongo.Orchestrator;
[BsonIgnoreExtraElements]
public sealed class OrchestratorRegistryDocument
{
[BsonId]
public string Id { get; set; } = string.Empty;
[BsonElement("tenant")]
public string Tenant { get; set; } = string.Empty;
[BsonElement("connectorId")]
public string ConnectorId { get; set; } = string.Empty;
[BsonElement("source")]
public string Source { get; set; } = string.Empty;
[BsonElement("capabilities")]
public IReadOnlyCollection<string> Capabilities { get; set; } = Array.Empty<string>();
[BsonElement("authRef")]
public string AuthRef { get; set; } = string.Empty;
[BsonElement("schedule")]
public OrchestratorScheduleDocument Schedule { get; set; } = new();
[BsonElement("ratePolicy")]
public OrchestratorRatePolicyDocument RatePolicy { get; set; } = new();
[BsonElement("artifactKinds")]
public IReadOnlyCollection<string> ArtifactKinds { get; set; } = Array.Empty<string>();
[BsonElement("lockKey")]
public string LockKey { get; set; } = string.Empty;
[BsonElement("egressGuard")]
public OrchestratorEgressGuardDocument EgressGuard { get; set; } = new();
[BsonElement("createdAt")]
public DateTime CreatedAt { get; set; }
= DateTime.SpecifyKind(DateTime.UnixEpoch, DateTimeKind.Utc);
[BsonElement("updatedAt")]
public DateTime UpdatedAt { get; set; }
= DateTime.SpecifyKind(DateTime.UnixEpoch, DateTimeKind.Utc);
}
[BsonIgnoreExtraElements]
public sealed class OrchestratorScheduleDocument
{
[BsonElement("cron")]
public string Cron { get; set; } = string.Empty;
[BsonElement("timeZone")]
public string TimeZone { get; set; } = "UTC";
[BsonElement("maxParallelRuns")]
public int MaxParallelRuns { get; set; }
= 1;
[BsonElement("maxLagMinutes")]
public int MaxLagMinutes { get; set; }
= 0;
}
[BsonIgnoreExtraElements]
public sealed class OrchestratorRatePolicyDocument
{
[BsonElement("rpm")]
public int Rpm { get; set; }
= 0;
[BsonElement("burst")]
public int Burst { get; set; }
= 0;
[BsonElement("cooldownSeconds")]
public int CooldownSeconds { get; set; }
= 0;
}
[BsonIgnoreExtraElements]
public sealed class OrchestratorEgressGuardDocument
{
[BsonElement("allowlist")]
public IReadOnlyCollection<string> Allowlist { get; set; } = Array.Empty<string>();
[BsonElement("airgapMode")]
public bool AirgapMode { get; set; }
= true;
}
internal static class OrchestratorRegistryDocumentExtensions
{
public static OrchestratorRegistryDocument FromRecord(OrchestratorRegistryRecord record)
{
ArgumentNullException.ThrowIfNull(record);
return new OrchestratorRegistryDocument
{
Id = BuildId(record.Tenant, record.ConnectorId),
Tenant = record.Tenant,
ConnectorId = record.ConnectorId,
Source = record.Source,
Capabilities = record.Capabilities,
AuthRef = record.AuthRef,
Schedule = new OrchestratorScheduleDocument
{
Cron = record.Schedule.Cron,
TimeZone = record.Schedule.TimeZone,
MaxParallelRuns = record.Schedule.MaxParallelRuns,
MaxLagMinutes = record.Schedule.MaxLagMinutes,
},
RatePolicy = new OrchestratorRatePolicyDocument
{
Rpm = record.RatePolicy.Rpm,
Burst = record.RatePolicy.Burst,
CooldownSeconds = record.RatePolicy.CooldownSeconds,
},
ArtifactKinds = record.ArtifactKinds,
LockKey = record.LockKey,
EgressGuard = new OrchestratorEgressGuardDocument
{
Allowlist = record.EgressGuard.Allowlist,
AirgapMode = record.EgressGuard.AirgapMode,
},
CreatedAt = record.CreatedAt.UtcDateTime,
UpdatedAt = record.UpdatedAt.UtcDateTime,
};
}
public static OrchestratorRegistryRecord ToRecord(this OrchestratorRegistryDocument document)
{
ArgumentNullException.ThrowIfNull(document);
return new OrchestratorRegistryRecord(
document.Tenant,
document.ConnectorId,
document.Source,
document.Capabilities,
document.AuthRef,
new OrchestratorSchedule(
document.Schedule.Cron,
document.Schedule.TimeZone,
document.Schedule.MaxParallelRuns,
document.Schedule.MaxLagMinutes),
new OrchestratorRatePolicy(
document.RatePolicy.Rpm,
document.RatePolicy.Burst,
document.RatePolicy.CooldownSeconds),
document.ArtifactKinds,
document.LockKey,
new OrchestratorEgressGuard(document.EgressGuard.Allowlist, document.EgressGuard.AirgapMode),
DateTime.SpecifyKind(document.CreatedAt, DateTimeKind.Utc),
DateTime.SpecifyKind(document.UpdatedAt, DateTimeKind.Utc));
}
private static string BuildId(string tenant, string connectorId)
=> string.Create(CultureInfo.InvariantCulture, $"{tenant}:{connectorId}");
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
namespace StellaOps.Concelier.Storage.Mongo.Orchestrator;
public sealed record OrchestratorRegistryRecord(
string Tenant,
string ConnectorId,
string Source,
IReadOnlyCollection<string> Capabilities,
string AuthRef,
OrchestratorSchedule Schedule,
OrchestratorRatePolicy RatePolicy,
IReadOnlyCollection<string> ArtifactKinds,
string LockKey,
OrchestratorEgressGuard EgressGuard,
DateTimeOffset CreatedAt,
DateTimeOffset UpdatedAt);
public sealed record OrchestratorSchedule(
string Cron,
string TimeZone,
int MaxParallelRuns,
int MaxLagMinutes);
public sealed record OrchestratorRatePolicy(
int Rpm,
int Burst,
int CooldownSeconds);
public sealed record OrchestratorEgressGuard(
IReadOnlyCollection<string> Allowlist,
bool AirgapMode);

View File

@@ -23,6 +23,7 @@ using StellaOps.Concelier.Storage.Mongo.Migrations;
using StellaOps.Concelier.Storage.Mongo.Observations;
using StellaOps.Concelier.Core.Observations;
using StellaOps.Concelier.Storage.Mongo.Linksets;
using StellaOps.Concelier.Storage.Mongo.Orchestrator;
namespace StellaOps.Concelier.Storage.Mongo;
@@ -81,17 +82,17 @@ public static class ServiceCollectionExtensions
services.AddSingleton<IAdvisoryObservationLookup, AdvisoryObservationLookup>();
services.AddSingleton<IAdvisoryEventRepository, MongoAdvisoryEventRepository>();
services.AddSingleton<IAdvisoryEventLog, AdvisoryEventLog>();
services.AddSingleton<MongoAdvisoryObservationEventPublisher>();
services.AddSingleton<IAdvisoryObservationEventPublisher, MongoAdvisoryObservationEventPublisher>();
services.AddSingleton<NatsAdvisoryObservationEventPublisher>();
services.AddSingleton<IAdvisoryObservationEventPublisher>(sp =>
services.AddSingleton<IAdvisoryObservationEventTransport>(sp =>
{
var options = sp.GetRequiredService<IOptions<AdvisoryObservationEventPublisherOptions>>().Value;
if (string.Equals(options.Transport, "nats", StringComparison.OrdinalIgnoreCase))
if (options.Enabled && string.Equals(options.Transport, "nats", StringComparison.OrdinalIgnoreCase))
{
return sp.GetRequiredService<NatsAdvisoryObservationEventPublisher>();
}
return sp.GetRequiredService<MongoAdvisoryObservationEventPublisher>();
return NullAdvisoryObservationEventTransport.Instance;
});
services.AddSingleton<IAdvisoryObservationEventOutbox, MongoAdvisoryObservationEventOutbox>();
services.AddSingleton<IAdvisoryRawRepository, MongoAdvisoryRawRepository>();
@@ -129,6 +130,24 @@ public static class ServiceCollectionExtensions
return database.GetCollection<AdvisoryObservationEventDocument>(MongoStorageDefaults.Collections.AdvisoryObservationEvents);
});
services.AddSingleton<IMongoCollection<OrchestratorRegistryDocument>>(static sp =>
{
var database = sp.GetRequiredService<IMongoDatabase>();
return database.GetCollection<OrchestratorRegistryDocument>(MongoStorageDefaults.Collections.OrchestratorRegistry);
});
services.AddSingleton<IMongoCollection<OrchestratorCommandDocument>>(static sp =>
{
var database = sp.GetRequiredService<IMongoDatabase>();
return database.GetCollection<OrchestratorCommandDocument>(MongoStorageDefaults.Collections.OrchestratorCommands);
});
services.AddSingleton<IMongoCollection<OrchestratorHeartbeatDocument>>(static sp =>
{
var database = sp.GetRequiredService<IMongoDatabase>();
return database.GetCollection<OrchestratorHeartbeatDocument>(MongoStorageDefaults.Collections.OrchestratorHeartbeats);
});
services.AddSingleton<IMongoCollection<AdvisoryLinksetDocument>>(static sp =>
{
var database = sp.GetRequiredService<IMongoDatabase>();
@@ -136,6 +155,7 @@ public static class ServiceCollectionExtensions
});
services.AddHostedService<RawDocumentRetentionService>();
services.AddHostedService<AdvisoryObservationTransportWorker>();
services.AddSingleton<MongoMigrationRunner>();
services.AddSingleton<IMongoMigration, EnsureDocumentExpiryIndexesMigration>();
@@ -149,6 +169,9 @@ public static class ServiceCollectionExtensions
services.AddSingleton<IMongoMigration, EnsureAdvisoryEventCollectionsMigration>();
services.AddSingleton<IMongoMigration, EnsureAdvisoryObservationEventCollectionMigration>();
services.AddSingleton<IMongoMigration, SemVerStyleBackfillMigration>();
services.AddSingleton<IMongoMigration, EnsureOrchestratorCollectionsMigration>();
services.AddSingleton<IOrchestratorRegistryStore, MongoOrchestratorRegistryStore>();
services.AddSingleton<IHostedService, AdvisoryObservationTransportWorker>();

View File

@@ -60,6 +60,44 @@ public sealed class AdvisoryObservationAggregationTests
Assert.Null(normalized); // no purls supplied
}
[Fact]
public void BuildAggregateLinkset_ComputesConflictsAndConfidenceFromObservations()
{
var obsA = CreateObservation(
"obs-a",
new RawLinkset
{
Aliases = ImmutableArray.Create("CVE-2025-0001"),
PackageUrls = ImmutableArray.Create("pkg:npm/foo@1.0.0"),
References = ImmutableArray.Create(new RawReference("advisory", "https://a.example/advisory"))
},
fetchedAt: DateTimeOffset.UtcNow.AddHours(-1),
vendor: "vendor-a");
var obsB = CreateObservation(
"obs-b",
new RawLinkset
{
Aliases = ImmutableArray.Create("GHSA-xxxx-xxxx"),
PackageUrls = ImmutableArray.Create("pkg:npm/foo@2.0.0"),
References = ImmutableArray.Create(new RawReference("advisory", "https://b.example/advisory"))
},
fetchedAt: DateTimeOffset.UtcNow,
vendor: "vendor-b");
var method = typeof(AdvisoryObservationQueryService).GetMethod(
"BuildAggregateLinkset",
BindingFlags.NonPublic | BindingFlags.Static)!;
var aggregate = (AdvisoryObservationLinksetAggregate)method.Invoke(
null,
new object?[] { ImmutableArray.Create(obsA, obsB) })!;
Assert.Contains(aggregate.Conflicts, c => c.Reason == "alias-inconsistency");
Assert.Contains(aggregate.Conflicts, c => c.Reason == "affected-range-divergence");
Assert.True(aggregate.Confidence is > 0.0 and < 1.0);
}
[Fact]
public void BuildAggregateLinkset_EmptyInputReturnsEmptyArrays()
{
@@ -75,13 +113,17 @@ public sealed class AdvisoryObservationAggregationTests
Assert.True(aggregate.Relationships.IsEmpty);
}
private static AdvisoryObservation CreateObservation(string id, RawLinkset rawLinkset)
private static AdvisoryObservation CreateObservation(
string id,
RawLinkset rawLinkset,
DateTimeOffset? fetchedAt = null,
string vendor = "vendor")
{
var source = new AdvisoryObservationSource("vendor", "stream", "api");
var source = new AdvisoryObservationSource(vendor, "stream", "api");
var upstream = new AdvisoryObservationUpstream(
"adv-id",
null,
DateTimeOffset.UtcNow,
(fetchedAt ?? DateTimeOffset.UtcNow),
DateTimeOffset.UtcNow,
"sha256:abc",
new AdvisoryObservationSignature(false, null, null, null));

View File

@@ -36,7 +36,7 @@ public sealed class ConcelierMongoLinksetStoreTests : IClassFixture<MongoIntegra
0.82,
new List<AdvisoryLinksetConflict>
{
new("severity", "disagree", new[] { "HIGH", "MEDIUM" })
new("severity", "disagree", new[] { "HIGH", "MEDIUM" }, new[] { "source-a", "source-b" })
},
DateTimeOffset.UtcNow,
"job-1");
@@ -54,6 +54,7 @@ public sealed class ConcelierMongoLinksetStoreTests : IClassFixture<MongoIntegra
Assert.Single(document.Conflicts!);
Assert.Equal("severity", document.Conflicts![0].Field);
Assert.Equal("disagree", document.Conflicts![0].Reason);
Assert.Equal(new[] { "source-a", "source-b" }, document.Conflicts![0].SourceIds);
}
[Fact]
@@ -72,7 +73,8 @@ public sealed class ConcelierMongoLinksetStoreTests : IClassFixture<MongoIntegra
{
Field = "references",
Reason = "mismatch",
Values = new List<string> { "url1", "url2" }
Values = new List<string> { "url1", "url2" },
SourceIds = new List<string> { "src-a", "src-b" }
}
},
CreatedAt = DateTime.UtcNow
@@ -90,6 +92,7 @@ public sealed class ConcelierMongoLinksetStoreTests : IClassFixture<MongoIntegra
Assert.NotNull(model.Conflicts);
Assert.Single(model.Conflicts!);
Assert.Equal("references", model.Conflicts![0].Field);
Assert.Equal(new[] { "src-a", "src-b" }, model.Conflicts![0].SourceIds);
}
[Fact]

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Immutable;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Concelier.Core.Observations;
using StellaOps.Concelier.Storage.Mongo.Observations;
using StellaOps.Concelier.Models.Observations;
using Xunit;
namespace StellaOps.Concelier.Storage.Mongo.Tests.Observations;
public class AdvisoryObservationTransportWorkerTests
{
[Fact]
public async Task Worker_publishes_outbox_entries_and_marks_published_once()
{
var evt = new AdvisoryObservationUpdatedEvent(
Guid.NewGuid(),
"tenant-1",
"obs-1",
"adv-1",
new Models.Observations.AdvisoryObservationSource("vendor", "stream", "api", "1.0.0"),
new AdvisoryObservationLinksetSummary(
ImmutableArray<string>.Empty,
ImmutableArray<string>.Empty,
ImmutableArray<string>.Empty,
ImmutableArray<string>.Empty,
ImmutableArray<AdvisoryObservationRelationshipSummary>.Empty),
"doc-sha",
"hash-1",
DateTimeOffset.UtcNow,
ReplayCursor: "cursor-1",
supersedesId: null,
traceId: "trace-1");
var outbox = new FakeOutbox(evt);
var transport = new FakeTransport();
var options = Options.Create(new AdvisoryObservationEventPublisherOptions
{
Enabled = true,
Transport = "nats",
Subject = "subject",
Stream = "stream",
NatsUrl = "nats://localhost:4222"
});
var worker = new AdvisoryObservationTransportWorker(outbox, transport, options, NullLogger<AdvisoryObservationTransportWorker>.Instance);
await worker.StartAsync(CancellationToken.None);
await Task.Delay(150, CancellationToken.None);
await worker.StopAsync(CancellationToken.None);
Assert.Equal(1, transport.Sent.Count);
Assert.Equal(evt.EventId, transport.Sent[0].EventId);
Assert.Equal(1, outbox.MarkedCount);
}
private sealed class FakeOutbox : IAdvisoryObservationEventOutbox
{
private readonly AdvisoryObservationUpdatedEvent _event;
private bool _dequeued;
public int MarkedCount { get; private set; }
public FakeOutbox(AdvisoryObservationUpdatedEvent @event)
{
_event = @event;
}
public Task<IReadOnlyCollection<AdvisoryObservationUpdatedEvent>> DequeueAsync(int take, CancellationToken cancellationToken)
{
if (_dequeued)
{
return Task.FromResult<IReadOnlyCollection<AdvisoryObservationUpdatedEvent>>(Array.Empty<AdvisoryObservationUpdatedEvent>());
}
_dequeued = true;
return Task.FromResult<IReadOnlyCollection<AdvisoryObservationUpdatedEvent>>(new[] { _event });
}
public Task MarkPublishedAsync(Guid eventId, DateTimeOffset publishedAt, CancellationToken cancellationToken)
{
MarkedCount++;
return Task.CompletedTask;
}
}
private sealed class FakeTransport : IAdvisoryObservationEventTransport
{
public List<AdvisoryObservationUpdatedEvent> Sent { get; } = new();
public Task SendAsync(AdvisoryObservationUpdatedEvent @event, CancellationToken cancellationToken)
{
Sent.Add(@event);
return Task.CompletedTask;
}
}
}

View File

@@ -603,6 +603,33 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
Assert.Equal("GHSA-2025-0001", evidence!.AdvisoryKey);
Assert.Equal(2, evidence.Records.Count);
Assert.All(evidence.Records, record => Assert.Equal("tenant-a", record.Tenant));
Assert.Null(evidence.Attestation);
}
[Fact]
public async Task AdvisoryEvidenceEndpoint_AttachesAttestationWhenBundleProvided()
{
await SeedAdvisoryRawDocumentsAsync(
CreateAdvisoryRawDocument("tenant-a", "vendor-x", "GHSA-2025-0003", "sha256:201", new BsonDocument("id", "GHSA-2025-0003:1")));
var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "..", ".."));
var sampleDir = Path.Combine(repoRoot, "docs", "samples", "evidence-bundle");
var tarPath = Path.Combine(sampleDir, "evidence-bundle-m0.tar.gz");
var manifestPath = Path.Combine(sampleDir, "manifest.json");
var transparencyPath = Path.Combine(sampleDir, "transparency.json");
using var client = _factory.CreateClient();
var requestUri = $"/vuln/evidence/advisories/GHSA-2025-0003?tenant=tenant-a&bundlePath={Uri.EscapeDataString(tarPath)}&manifestPath={Uri.EscapeDataString(manifestPath)}&transparencyPath={Uri.EscapeDataString(transparencyPath)}&pipelineVersion=git:test-sha";
var response = await client.GetAsync(requestUri);
response.EnsureSuccessStatusCode();
var evidence = await response.Content.ReadFromJsonAsync<AdvisoryEvidenceResponse>();
Assert.NotNull(evidence);
Assert.NotNull(evidence!.Attestation);
Assert.Equal("evidence-bundle-m0", evidence.Attestation!.SubjectName);
Assert.Equal("git:test-sha", evidence.Attestation.PipelineVersion);
Assert.Equal(tarPath, evidence.Attestation.EvidenceBundlePath);
}
[Fact]

View File

@@ -0,0 +1,35 @@
using System;
using System.Text.Json.Serialization;
namespace StellaOps.Excititor.WebService.Contracts;
/// <summary>
/// Envelope for air-gapped VEX bundle imports.
/// Mirrors the thin mirror bundle schema and carries signing metadata.
/// </summary>
public sealed class AirgapImportRequest
{
[JsonPropertyName("bundleId")]
public string? BundleId { get; init; }
[JsonPropertyName("mirrorGeneration")]
public string? MirrorGeneration { get; init; }
[JsonPropertyName("signedAt")]
public DateTimeOffset? SignedAt { get; init; }
[JsonPropertyName("publisher")]
public string? Publisher { get; init; }
[JsonPropertyName("payloadHash")]
public string? PayloadHash { get; init; }
[JsonPropertyName("payloadUrl")]
public string? PayloadUrl { get; init; }
[JsonPropertyName("signature")]
public string? Signature { get; init; }
[JsonPropertyName("transparencyLog")]
public string? TransparencyLog { get; init; }
}

View File

@@ -48,6 +48,7 @@ services.AddCsafNormalizer();
services.AddCycloneDxNormalizer();
services.AddOpenVexNormalizer();
services.AddSingleton<IVexSignatureVerifier, NoopVexSignatureVerifier>();
services.AddSingleton<AirgapImportValidator>();
services.AddScoped<IVexIngestOrchestrator, VexIngestOrchestrator>();
services.AddScoped<IVexObservationLookup, MongoVexObservationLookup>();
services.AddOptions<ExcititorObservabilityOptions>()
@@ -140,6 +141,33 @@ app.MapGet("/excititor/status", async (HttpContext context,
app.MapHealthChecks("/excititor/health");
app.MapPost("/airgap/v1/vex/import", async (
[FromServices] AirgapImportValidator validator,
[FromServices] TimeProvider timeProvider,
[FromBody] AirgapImportRequest request,
CancellationToken cancellationToken) =>
{
var errors = validator.Validate(request, timeProvider.GetUtcNow());
if (errors.Count > 0)
{
var first = errors[0];
return Results.BadRequest(new
{
error = new
{
code = first.Code,
message = first.Message
}
});
}
return Results.Accepted($"/airgap/v1/vex/import/{request.BundleId}", new
{
bundleId = request.BundleId,
generation = request.MirrorGeneration
});
});
app.MapPost("/v1/attestations/verify", async (
[FromServices] IVexAttestationClient attestationClient,
[FromBody] AttestationVerifyRequest request,

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Globalization;
namespace StellaOps.Excititor.WebService.Services;
internal sealed class AirgapImportValidator
{
private static readonly TimeSpan AllowedSkew = TimeSpan.FromSeconds(5);
public IReadOnlyList<ValidationError> Validate(AirgapImportRequest request, DateTimeOffset nowUtc)
{
var errors = new List<ValidationError>();
if (request is null)
{
errors.Add(new ValidationError("invalid_request", "Request body is required."));
return errors;
}
if (string.IsNullOrWhiteSpace(request.BundleId))
{
errors.Add(new ValidationError("bundle_id_missing", "bundleId is required."));
}
if (string.IsNullOrWhiteSpace(request.MirrorGeneration))
{
errors.Add(new ValidationError("mirror_generation_missing", "mirrorGeneration is required."));
}
if (string.IsNullOrWhiteSpace(request.Publisher))
{
errors.Add(new ValidationError("publisher_missing", "publisher is required."));
}
if (string.IsNullOrWhiteSpace(request.PayloadHash))
{
errors.Add(new ValidationError("payload_hash_missing", "payloadHash is required."));
}
if (string.IsNullOrWhiteSpace(request.Signature))
{
errors.Add(new ValidationError("AIRGAP_SIGNATURE_MISSING", "signature is required for air-gapped imports."));
}
if (request.SignedAt is null)
{
errors.Add(new ValidationError("signed_at_missing", "signedAt is required."));
}
else
{
var delta = (nowUtc - request.SignedAt.Value).Duration();
if (delta > AllowedSkew)
{
errors.Add(new ValidationError(
"AIRGAP_PAYLOAD_STALE",
$"signedAt exceeds allowed skew of {AllowedSkew.TotalSeconds.ToString(CultureInfo.InvariantCulture)} seconds."));
}
}
return errors;
}
public readonly record struct ValidationError(string Code, string Message);
}

View File

@@ -0,0 +1,54 @@
using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using StellaOps.Excititor.WebService.Contracts;
using Xunit;
namespace StellaOps.Excititor.WebService.Tests;
public class AirgapImportEndpointTests : IClassFixture<TestWebApplicationFactory>
{
private readonly HttpClient _client;
public AirgapImportEndpointTests(TestWebApplicationFactory factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task Import_returns_bad_request_when_signature_missing()
{
var request = new AirgapImportRequest
{
BundleId = "bundle-123",
MirrorGeneration = "gen-1",
SignedAt = DateTimeOffset.UtcNow,
Publisher = "mirror-test",
PayloadHash = "sha256:abc"
};
var response = await _client.PostAsJsonAsync("/airgap/v1/vex/import", request);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
var json = await response.Content.ReadFromJsonAsync<JsonElement>();
Assert.Equal("AIRGAP_SIGNATURE_MISSING", json.GetProperty("error").GetProperty("code").GetString());
}
[Fact]
public async Task Import_accepts_valid_payload()
{
var request = new AirgapImportRequest
{
BundleId = "bundle-123",
MirrorGeneration = "gen-1",
SignedAt = DateTimeOffset.UtcNow,
Publisher = "mirror-test",
PayloadHash = "sha256:abc",
Signature = "sig"
};
using var response = await _client.PostAsJsonAsync("/airgap/v1/vex/import", request);
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
}
}

View File

@@ -1,6 +1,11 @@
using System.Net;
using System.Net.Http;
using System.Text;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Notifier.Tests.Support;
using StellaOps.Notifier.WebService;
using StellaOps.Notify.Storage.Mongo.Repositories;
using Xunit;
namespace StellaOps.Notifier.Tests;

View File

@@ -12,6 +12,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
@@ -28,6 +29,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Notifier.WebService\StellaOps.Notifier.WebService.csproj" />
<ProjectReference Include="..\StellaOps.Notifier.Worker\StellaOps.Notifier.Worker.csproj" />
</ItemGroup>
</Project>

View File

@@ -6,11 +6,11 @@ using StellaOps.Notifier.Worker.Processing;
namespace StellaOps.Notifier.Tests.Support;
public sealed class TestEgressSloSink : IEgressSloSink
internal sealed class TestEgressSloSink : IEgressSloSink
{
private readonly ConcurrentBag<EgressSloContext> _contexts = new();
public IReadOnlyCollection<EgressSloContext> Contexts => _contexts;
internal IReadOnlyCollection<EgressSloContext> Contexts => _contexts;
public Task PublishAsync(EgressSloContext context, CancellationToken cancellationToken)
{

View File

@@ -126,10 +126,6 @@ app.MapGet("/.well-known/openapi", (HttpContext context, OpenApiDocumentCache ca
return Results.Content(cache.Document, "application/yaml");
});
app.Run();
public partial class Program;
static object Error(string code, string message, HttpContext context) => new
{
error = new
@@ -139,3 +135,7 @@ static object Error(string code, string message, HttpContext context) => new
traceId = context.TraceIdentifier
}
};
app.Run();
public partial class Program;

View File

@@ -11,6 +11,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.0-rc.2.25502.107" />
</ItemGroup>

View File

@@ -7,9 +7,9 @@
| NOTIFY-OAS-61-001 | DONE (2025-11-17) | Notifications Service Guild · API Contracts Guild | OAS updated with rules/templates/incidents/quiet hours and standard error envelope. |
| NOTIFY-OAS-61-002 | DONE (2025-11-17) | Notifications Service Guild | `.well-known/openapi` discovery endpoint with scope metadata implemented. |
| NOTIFY-OAS-62-001 | DONE (2025-11-17) | Notifications Service Guild · SDK Generator Guild | SDK usage examples + smoke tests (depends on 61-002). |
| NOTIFY-OAS-63-001 | TODO | Notifications Service Guild · API Governance Guild | Deprecation headers + template notices for retiring APIs (depends on 62-001). |
| NOTIFY-OBS-51-001 | TODO | Notifications Service Guild · Observability Guild | Integrate SLO evaluator webhooks once schema lands. |
| NOTIFY-OBS-55-001 | TODO | Notifications Service Guild · Ops Guild | Incident mode start/stop notifications; quiet-hour overrides. |
| NOTIFY-OAS-63-001 | DONE (2025-11-17) | Notifications Service Guild · API Governance Guild | Deprecation headers + template notices for retiring APIs (depends on 62-001). |
| NOTIFY-OBS-51-001 | DONE (2025-11-22) | Notifications Service Guild · Observability Guild | SLO webhook sink validated (`HttpEgressSloSinkTests`, `EventProcessorTests`); TRX: `StellaOps.Notifier.Tests/TestResults/notifier-slo-tests.trx`. |
| NOTIFY-OBS-55-001 | DONE (2025-11-22) | Notifications Service Guild · Ops Guild | Incident mode start/stop notifications; templates + importable rules with quiet-hour overrides and legal logging metadata. |
| NOTIFY-RISK-66-001 | TODO | Notifications Service Guild · Risk Engine Guild | Trigger risk severity escalation/downgrade notifications (waiting on Policy export). |
| NOTIFY-RISK-67-001 | TODO | Notifications Service Guild · Policy Guild | Notify when risk profiles publish/deprecate/threshold-change (depends on 66-001). |
| NOTIFY-RISK-68-001 | TODO | Notifications Service Guild | Per-profile routing rules + quiet hours for risk alerts (depends on 67-001). |

View File

@@ -0,0 +1,51 @@
[
{
"ruleId": "incident-start-default",
"tenantId": "tenant-a",
"name": "Incident mode activated",
"enabled": true,
"match": {
"eventKinds": [
"incident.mode.start"
]
},
"actions": [
{
"actionId": "incident-start-slack",
"channel": "slack-ops",
"template": "tmpl-incident-start",
"metadata": {
"trace_link": "{{payload.links.trace}}",
"evidence_link": "{{payload.links.evidence}}",
"retention_note": "Retention extended to {{payload.retentionDays}} days while incident mode is active.",
"quiet_hours_override": "true",
"legal_jurisdiction": "{{payload.legal.jurisdiction}}",
"legal_ticket": "{{payload.legal.ticket}}"
}
}
]
},
{
"ruleId": "incident-stop-default",
"tenantId": "tenant-a",
"name": "Incident mode cleared",
"enabled": true,
"match": {
"eventKinds": [
"incident.mode.stop"
]
},
"actions": [
{
"actionId": "incident-stop-email",
"channel": "email-compliance",
"template": "tmpl-incident-stop",
"metadata": {
"summary_link": "{{payload.links.timeline}}",
"retention_reset_note": "Retention reverts to baseline {{payload.retentionBaselineDays}} days.",
"legal_log_path": "{{payload.legal.logPath}}"
}
}
]
}
]

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using StellaOps.Notify.Storage.Mongo.Internal;
@@ -22,8 +23,13 @@ internal sealed class EnsurePackApprovalsCollectionMigration : INotifyMongoMigra
.ListCollectionNamesAsync(cancellationToken: cancellationToken)
.ConfigureAwait(false);
var existing = await cursor.ToListAsync(cancellationToken).ConfigureAwait(false);
if (existing.Contains(target, StringComparer.Ordinal))
var existing = new HashSet<string>(StringComparer.Ordinal);
while (await cursor.MoveNextAsync(cancellationToken).ConfigureAwait(false))
{
existing.UnionWith(cursor.Current);
}
if (existing.Contains(target))
{
return;
}

View File

@@ -18,6 +18,8 @@ public sealed class NotifyMongoOptions
public string DigestsCollection { get; set; } = "digests";
public string PackApprovalsCollection { get; set; } = "pack_approvals";
public string LocksCollection { get; set; } = "locks";
public string AuditCollection { get; set; } = "audit";

View File

@@ -0,0 +1,67 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Mongo2Go;
using MongoDB.Bson;
using MongoDB.Driver;
using StellaOps.Concelier.Storage.Mongo.Migrations;
namespace StellaOps.Concelier.Storage.Mongo.Tests;
public sealed class EnsureOrchestratorCollectionsMigrationTests : IAsyncLifetime
{
private MongoDbRunner _runner = null!;
private IMongoDatabase _database = null!;
public Task InitializeAsync()
{
_runner = MongoDbRunner.Start(singleNodeReplSet: true);
var client = new MongoClient(_runner.ConnectionString);
_database = client.GetDatabase("orch-migration-tests");
return Task.CompletedTask;
}
public Task DisposeAsync()
{
_runner.Dispose();
return Task.CompletedTask;
}
[Fact]
public async Task CreatesOrchestratorCollectionsAndIndexes()
{
var migration = new EnsureOrchestratorCollectionsMigration();
await migration.ApplyAsync(_database, CancellationToken.None);
var collections = await _database.ListCollectionNames().ToListAsync();
collections.Should().Contain(
new[]
{
MongoStorageDefaults.Collections.OrchestratorRegistry,
MongoStorageDefaults.Collections.OrchestratorCommands,
MongoStorageDefaults.Collections.OrchestratorHeartbeats,
});
var registryIndexes = await GetIndexNamesAsync(MongoStorageDefaults.Collections.OrchestratorRegistry);
registryIndexes.Should().Contain("orch_registry_tenant_connector");
var commandIndexes = await GetIndexNamesAsync(MongoStorageDefaults.Collections.OrchestratorCommands);
commandIndexes.Should().Contain("orch_cmd_tenant_connector_run_seq");
commandIndexes.Should().Contain("orch_cmd_expiresAt_ttl");
var heartbeatIndexes = await GetIndexNamesAsync(MongoStorageDefaults.Collections.OrchestratorHeartbeats);
heartbeatIndexes.Should().Contain("orch_hb_tenant_connector_run_seq");
}
private async Task<IReadOnlyCollection<string>> GetIndexNamesAsync(string collection)
{
var docs = await _database.GetCollection<BsonDocument>(collection)
.Indexes
.List()
.ToListAsync();
return docs.Select(d => d["name"].AsString).ToArray();
}
}

View File

@@ -0,0 +1,130 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Mongo2Go;
using MongoDB.Driver;
using StellaOps.Concelier.Storage.Mongo.Migrations;
using StellaOps.Concelier.Storage.Mongo.Orchestrator;
namespace StellaOps.Concelier.Storage.Mongo.Tests;
public sealed class MongoOrchestratorRegistryStoreTests : IAsyncLifetime
{
private MongoDbRunner _runner = null!;
private IMongoDatabase _database = null!;
private MongoOrchestratorRegistryStore _store = null!;
public Task InitializeAsync()
{
_runner = MongoDbRunner.Start(singleNodeReplSet: true);
var client = new MongoClient(_runner.ConnectionString);
_database = client.GetDatabase("orch-store-tests");
// ensure collections/indexes present
var migration = new EnsureOrchestratorCollectionsMigration();
migration.ApplyAsync(_database, CancellationToken.None).GetAwaiter().GetResult();
_store = new MongoOrchestratorRegistryStore(
_database.GetCollection<OrchestratorRegistryDocument>(MongoStorageDefaults.Collections.OrchestratorRegistry),
_database.GetCollection<OrchestratorCommandDocument>(MongoStorageDefaults.Collections.OrchestratorCommands),
_database.GetCollection<OrchestratorHeartbeatDocument>(MongoStorageDefaults.Collections.OrchestratorHeartbeats));
return Task.CompletedTask;
}
public Task DisposeAsync()
{
_runner.Dispose();
return Task.CompletedTask;
}
[Fact]
public async Task UpsertAndFetchRegistryRoundTrips()
{
var record = new OrchestratorRegistryRecord(
Tenant: "tenant-a",
ConnectorId: "icscisa",
Source: "icscisa",
Capabilities: new[] { "observations", "linksets" },
AuthRef: "secret:concelier/icscisa/api-key",
Schedule: new OrchestratorSchedule("*/30 * * * *", "UTC", 1, 120),
RatePolicy: new OrchestratorRatePolicy(60, 10, 30),
ArtifactKinds: new[] { "raw-advisory", "linkset" },
LockKey: "concelier:tenant-a:icscisa",
EgressGuard: new OrchestratorEgressGuard(new[] { "icscert.kisa.or.kr" }, true),
CreatedAt: DateTimeOffset.Parse("2025-11-20T00:00:00Z"),
UpdatedAt: DateTimeOffset.Parse("2025-11-21T00:00:00Z"));
await _store.UpsertAsync(record, CancellationToken.None);
var fetched = await _store.GetAsync("tenant-a", "icscisa", CancellationToken.None);
fetched.Should().NotBeNull();
fetched!.ConnectorId.Should().Be("icscisa");
fetched.Schedule.Cron.Should().Be("*/30 * * * *");
fetched.RatePolicy.Burst.Should().Be(10);
fetched.EgressGuard.AirgapMode.Should().BeTrue();
}
[Fact]
public async Task EnqueueAndReadCommandsOrdersBySequence()
{
var runId = Guid.NewGuid();
var first = new OrchestratorCommandRecord(
Tenant: "tenant-a",
ConnectorId: "icscisa",
RunId: runId,
Sequence: 1,
Command: OrchestratorCommandKind.Pause,
Throttle: null,
Backfill: null,
CreatedAt: DateTimeOffset.Parse("2025-11-20T00:00:00Z"),
ExpiresAt: null);
var second = new OrchestratorCommandRecord(
Tenant: "tenant-a",
ConnectorId: "icscisa",
RunId: runId,
Sequence: 2,
Command: OrchestratorCommandKind.Backfill,
Throttle: null,
Backfill: new OrchestratorBackfillRange("2024-01-01T00:00:00Z", "2024-02-01T00:00:00Z"),
CreatedAt: DateTimeOffset.Parse("2025-11-20T00:01:00Z"),
ExpiresAt: null);
await _store.EnqueueCommandAsync(second, CancellationToken.None);
await _store.EnqueueCommandAsync(first, CancellationToken.None);
var commands = await _store.GetPendingCommandsAsync("tenant-a", "icscisa", runId, afterSequence: 0, CancellationToken.None);
commands.Select(c => c.Sequence).Should().ContainInOrder(1, 2);
commands.Last().Backfill!.FromCursor.Should().Be("2024-01-01T00:00:00Z");
}
[Fact]
public async Task AppendsHeartbeats()
{
var heartbeat = new OrchestratorHeartbeatRecord(
Tenant: "tenant-a",
ConnectorId: "icscisa",
RunId: Guid.NewGuid(),
Sequence: 5,
Status: OrchestratorHeartbeatStatus.Running,
Progress: 42,
QueueDepth: 7,
LastArtifactHash: "abc",
LastArtifactKind: "normalized",
ErrorCode: null,
RetryAfterSeconds: null,
TimestampUtc: DateTimeOffset.Parse("2025-11-21T00:00:00Z"));
await _store.AppendHeartbeatAsync(heartbeat, CancellationToken.None);
var count = await _database
.GetCollection<OrchestratorHeartbeatDocument>(MongoStorageDefaults.Collections.OrchestratorHeartbeats)
.CountDocumentsAsync(FilterDefinition<OrchestratorHeartbeatDocument>.Empty);
count.Should().Be(1);
}
}