From 9f6e6f7fb314b06d08ae115c0e0a7e9776f74185 Mon Sep 17 00:00:00 2001 From: StellaOps Bot Date: Tue, 25 Nov 2025 22:09:44 +0200 Subject: [PATCH] up --- .gitea/workflows/mirror-sign.yml | 11 +- .gitea/workflows/policy-lint.yml | 67 +++ .gitea/workflows/policy-simulate.yml | 86 ++++ .gitea/workflows/sdk-publish.yml | 89 ++++ .gitea/workflows/signals-ci.yml | 72 ++++ docs/api/overview.md | 54 +++ docs/api/reference/README.md | 40 ++ docs/api/versioning.md | 41 ++ docs/contributing/api-contracts.md | 75 ++-- docs/examples/policies/sample-sbom.json | 19 + .../SPRINT_0114_0001_0003_concelier_iii.md | 13 +- .../SPRINT_0119_0001_0005_excititor_v.md | 13 +- .../SPRINT_0119_0001_0006_excititor_vi.md | 8 +- .../SPRINT_0129_0001_0001_policy_reasoning.md | 45 +- docs/implplan/SPRINT_0510_0001_0001_airgap.md | 14 +- docs/implplan/SPRINT_303_docs_tasks_md_iii.md | 24 +- docs/implplan/SPRINT_305_docs_tasks_md_v.md | 26 +- docs/implplan/SPRINT_306_docs_tasks_md_vi.md | 42 +- docs/implplan/SPRINT_506_ops_devops_iv.md | 53 ++- ...PRINT_0110_0001_0001_ingestion_evidence.md | 3 + .../SPRINT_0119_0001_0002_excititor_ii.md | 9 +- .../SPRINT_0119_0001_0003_excititor_iii.md | 9 +- docs/implplan/tasks-all.md | 384 +++++++++--------- docs/modules/attestor/airgap.md | 42 ++ .../graph-linkouts-implementation.md | 12 +- .../excititor/operations/vex-raw-validator.md | 31 ++ .../excititor/schemas/vex_raw.schema.json | 36 ++ docs/notifications/api.md | 42 ++ docs/notifications/channels.md | 51 +++ docs/notifications/escalations.md | 51 +++ docs/observability/aggregation.md | 37 ++ docs/observability/logging.md | 41 ++ docs/observability/metrics-and-slos.md | 42 ++ docs/observability/telemetry-standards.md | 38 ++ docs/observability/tracing.md | 37 ++ docs/operations/notifier-runbook.md | 58 +++ docs/operations/orchestrator-runbook.md | 39 ++ docs/orchestrator/api.md | 44 ++ docs/orchestrator/architecture.md | 53 +++ docs/orchestrator/cli.md | 35 ++ docs/orchestrator/console.md | 33 ++ docs/orchestrator/overview.md | 46 +++ docs/orchestrator/run-ledger.md | 36 ++ docs/policy/effective-severity.md | 56 +++ docs/schemas/artifacts.md | 49 +++ docs/security/aoc-invariants.md | 29 ++ docs/security/notifications-hardening.md | 37 ++ docs/security/secrets-handling.md | 20 + docs/slo/orchestrator-slo.md | 30 ++ helm/signals/values-signals.yaml | 35 ++ ops/devops/README-space.md | 28 ++ .../trx/concelier-storage-jobstore.trx | 266 ------------ .../trx/concelier-web-orch.trx | 22 +- .../trx/concelier-web-orch.trx | 30 ++ ops/devops/ci-110-runner/test-filters.md | 11 + .../grafana/policy-pipeline.json | 78 ++++ .../grafana/signals-pipeline.json | 74 ++++ ops/devops/observability/policy-alerts.yaml | 52 +++ ops/devops/observability/policy-playbook.md | 39 ++ ops/devops/observability/signals-alerts.yaml | 54 +++ ops/devops/observability/signals-playbook.md | 40 ++ ops/devops/orchestrator/README.md | 10 + ops/devops/orchestrator/alerts.yaml | 39 ++ .../grafana/orchestrator-overview.json | 21 + ops/devops/orchestrator/incident-response.md | 37 ++ ops/devops/policy-signing.md | 46 +++ ops/devops/rules/contracts-anchor.md | 19 + ops/devops/sdk/README.md | 38 ++ ops/devops/signals/Dockerfile | 22 + ops/devops/signals/README.md | 33 ++ ops/devops/signals/docker-compose.signals.yml | 52 +++ ops/devops/signals/signals.yaml | 15 + scripts/devops/cleanup-workspace.sh | 46 +++ scripts/orchestrator/probe.sh | 51 +++ scripts/orchestrator/replay-smoke.sh | 17 + scripts/policy/attest-verify.sh | 85 ++++ scripts/policy/batch-simulate.sh | 49 +++ scripts/policy/rotate-key.sh | 34 ++ scripts/policy/sign-policy.sh | 50 +++ scripts/sdk/generate-cert.sh | 34 ++ scripts/sdk/publish.sh | 36 ++ scripts/sdk/sign-packages.sh | 43 ++ scripts/signals/build.sh | 15 + src/AirGap/AGENTS.md | 42 ++ .../Contracts/EvidenceSnapshotContracts.cs | 1 + .../StellaOps.Concelier.WebService/Program.cs | 138 +++---- .../Services/IncidentFileStore.cs | 1 + .../MongoStorageOptions.cs | 36 +- .../ServiceCollectionExtensions.cs | 34 +- .../OrchestratorEndpointsTests.cs | 196 +++++++++ .../Services/IncidentFileStoreTests.cs | 1 + .../Contracts/GraphStatusContracts.cs | 17 + .../Contracts/GraphTooltipContracts.cs | 25 ++ .../Graph/GraphStatusFactory.cs | 36 ++ .../Graph/GraphTooltipFactory.cs | 127 ++++++ .../Options/GraphOptions.cs | 2 + .../Program.Helpers.cs | 4 + .../StellaOps.Excititor.WebService/Program.cs | 118 ++++++ .../Migrations/VexRawSchemaMigration.cs | 115 ++++++ .../ServiceCollectionExtensions.cs | 1 + .../GraphStatusFactoryTests.cs | 90 ++++ .../GraphTooltipFactoryTests.cs | 137 +++++++ ...tellaOps.Excititor.WebService.Tests.csproj | 2 + .../Services/IRiskScoreResultStore.cs | 6 + .../Services/RiskScoreQueue.cs | 11 + .../RiskEngineApiTests.cs | 119 ++++++ .../StellaOps.RiskEngine.Tests.csproj | 24 +- .../Program.cs | 83 +++- .../Data/SampleData.cs | 13 + .../Models/VulnModels.cs | 7 + .../StellaOps.VulnExplorer.Api/Program.cs | 45 +- .../StellaOps.VulnExplorer.Api.csproj | 1 + .../StellaOps.VulnExplorer.Api/TASKS.md | 7 + .../StellaOps.VulnExplorer.Api.Tests.csproj | 3 +- .../VulnApiTests.cs | 17 + tools/run-airgap-bundle-tests.sh | 23 ++ 116 files changed, 4495 insertions(+), 730 deletions(-) create mode 100644 .gitea/workflows/policy-lint.yml create mode 100644 .gitea/workflows/policy-simulate.yml create mode 100644 .gitea/workflows/sdk-publish.yml create mode 100644 .gitea/workflows/signals-ci.yml create mode 100644 docs/api/overview.md create mode 100644 docs/api/reference/README.md create mode 100644 docs/api/versioning.md create mode 100644 docs/examples/policies/sample-sbom.json rename docs/implplan/{ => archived}/SPRINT_0119_0001_0002_excititor_ii.md (92%) rename docs/implplan/{ => archived}/SPRINT_0119_0001_0003_excititor_iii.md (88%) create mode 100644 docs/modules/attestor/airgap.md create mode 100644 docs/modules/excititor/operations/vex-raw-validator.md create mode 100644 docs/modules/excititor/schemas/vex_raw.schema.json create mode 100644 docs/notifications/api.md create mode 100644 docs/notifications/channels.md create mode 100644 docs/notifications/escalations.md create mode 100644 docs/observability/aggregation.md create mode 100644 docs/observability/logging.md create mode 100644 docs/observability/metrics-and-slos.md create mode 100644 docs/observability/telemetry-standards.md create mode 100644 docs/observability/tracing.md create mode 100644 docs/operations/notifier-runbook.md create mode 100644 docs/operations/orchestrator-runbook.md create mode 100644 docs/orchestrator/api.md create mode 100644 docs/orchestrator/architecture.md create mode 100644 docs/orchestrator/cli.md create mode 100644 docs/orchestrator/console.md create mode 100644 docs/orchestrator/overview.md create mode 100644 docs/orchestrator/run-ledger.md create mode 100644 docs/policy/effective-severity.md create mode 100644 docs/schemas/artifacts.md create mode 100644 docs/security/aoc-invariants.md create mode 100644 docs/security/notifications-hardening.md create mode 100644 docs/security/secrets-handling.md create mode 100644 docs/slo/orchestrator-slo.md create mode 100644 helm/signals/values-signals.yaml create mode 100644 ops/devops/README-space.md delete mode 100644 ops/devops/artifacts/ci-110/20251125T034529Z/trx/concelier-storage-jobstore.trx create mode 100644 ops/devops/artifacts/ci-110/20251125T041800Z/trx/concelier-web-orch.trx create mode 100644 ops/devops/ci-110-runner/test-filters.md create mode 100644 ops/devops/observability/grafana/policy-pipeline.json create mode 100644 ops/devops/observability/grafana/signals-pipeline.json create mode 100644 ops/devops/observability/policy-alerts.yaml create mode 100644 ops/devops/observability/policy-playbook.md create mode 100644 ops/devops/observability/signals-alerts.yaml create mode 100644 ops/devops/observability/signals-playbook.md create mode 100644 ops/devops/orchestrator/incident-response.md create mode 100644 ops/devops/policy-signing.md create mode 100644 ops/devops/rules/contracts-anchor.md create mode 100644 ops/devops/sdk/README.md create mode 100644 ops/devops/signals/Dockerfile create mode 100644 ops/devops/signals/README.md create mode 100644 ops/devops/signals/docker-compose.signals.yml create mode 100644 ops/devops/signals/signals.yaml create mode 100644 scripts/devops/cleanup-workspace.sh create mode 100644 scripts/orchestrator/probe.sh create mode 100644 scripts/orchestrator/replay-smoke.sh create mode 100644 scripts/policy/attest-verify.sh create mode 100644 scripts/policy/batch-simulate.sh create mode 100644 scripts/policy/rotate-key.sh create mode 100644 scripts/policy/sign-policy.sh create mode 100644 scripts/sdk/generate-cert.sh create mode 100644 scripts/sdk/publish.sh create mode 100644 scripts/sdk/sign-packages.sh create mode 100644 scripts/signals/build.sh create mode 100644 src/AirGap/AGENTS.md create mode 100644 src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/OrchestratorEndpointsTests.cs create mode 100644 src/Excititor/StellaOps.Excititor.WebService/Contracts/GraphStatusContracts.cs create mode 100644 src/Excititor/StellaOps.Excititor.WebService/Contracts/GraphTooltipContracts.cs create mode 100644 src/Excititor/StellaOps.Excititor.WebService/Graph/GraphStatusFactory.cs create mode 100644 src/Excititor/StellaOps.Excititor.WebService/Graph/GraphTooltipFactory.cs create mode 100644 src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo/Migrations/VexRawSchemaMigration.cs create mode 100644 src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/GraphStatusFactoryTests.cs create mode 100644 src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/GraphTooltipFactoryTests.cs create mode 100644 src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Tests/RiskEngineApiTests.cs create mode 100644 src/VulnExplorer/StellaOps.VulnExplorer.Api/TASKS.md create mode 100644 tools/run-airgap-bundle-tests.sh diff --git a/.gitea/workflows/mirror-sign.yml b/.gitea/workflows/mirror-sign.yml index 7b8866a57..12f777fe6 100644 --- a/.gitea/workflows/mirror-sign.yml +++ b/.gitea/workflows/mirror-sign.yml @@ -21,15 +21,20 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 10.0.100-rc.1.25451.107 + dotnet-version: 10.0.100-rc.2.25502.107 include-prerelease: true + - name: Verify signing prerequisites + run: scripts/mirror/check_signing_prereqs.sh + - name: Run mirror signing run: | - set -euo pipefail - scripts/mirror/check_signing_prereqs.sh scripts/mirror/ci-sign.sh + - name: Verify signed bundle + run: | + scripts/mirror/verify_thin_bundle.py out/mirror/thin/mirror-thin-v1.tar.gz + - name: Upload signed artifacts uses: actions/upload-artifact@v4 with: diff --git a/.gitea/workflows/policy-lint.yml b/.gitea/workflows/policy-lint.yml new file mode 100644 index 000000000..6c68dc1c9 --- /dev/null +++ b/.gitea/workflows/policy-lint.yml @@ -0,0 +1,67 @@ +name: Policy Lint & Smoke + +on: + pull_request: + paths: + - 'docs/policy/**' + - 'docs/examples/policies/**' + - 'src/Cli/**' + - '.gitea/workflows/policy-lint.yml' + push: + branches: [ main ] + paths: + - 'docs/policy/**' + - 'docs/examples/policies/**' + - 'src/Cli/**' + - '.gitea/workflows/policy-lint.yml' + +jobs: + policy-lint: + runs-on: ubuntu-22.04 + env: + DOTNET_NOLOGO: 1 + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1 + TZ: UTC + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET 10 RC + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.100-rc.2.25502.107 + include-prerelease: true + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: | + ~/.nuget/packages + local-nugets/packages + key: policy-lint-nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} + + - name: Restore CLI + run: | + dotnet restore src/Cli/StellaOps.Cli/StellaOps.Cli.csproj --configfile nuget.config + + - name: Lint policies (deterministic) + run: | + mkdir -p out/policy-lint + dotnet run --project src/Cli/StellaOps.Cli/StellaOps.Cli.csproj -- \ + policy lint docs/examples/policies/*.stella \ + --format json --no-color \ + > out/policy-lint/lint.json + + - name: Smoke simulate entrypoint + run: | + dotnet run --project src/Cli/StellaOps.Cli/StellaOps.Cli.csproj -- policy simulate --help > out/policy-lint/simulate-help.txt + + - name: Upload lint artifacts + uses: actions/upload-artifact@v4 + with: + name: policy-lint + path: out/policy-lint + retention-days: 7 diff --git a/.gitea/workflows/policy-simulate.yml b/.gitea/workflows/policy-simulate.yml new file mode 100644 index 000000000..4e0df904a --- /dev/null +++ b/.gitea/workflows/policy-simulate.yml @@ -0,0 +1,86 @@ +name: Policy Simulation + +on: + pull_request: + paths: + - 'docs/policy/**' + - 'docs/examples/policies/**' + - 'scripts/policy/**' + - '.gitea/workflows/policy-simulate.yml' + push: + branches: [ main ] + paths: + - 'docs/policy/**' + - 'docs/examples/policies/**' + - 'scripts/policy/**' + - '.gitea/workflows/policy-simulate.yml' + +jobs: + policy-simulate: + runs-on: ubuntu-22.04 + env: + DOTNET_NOLOGO: 1 + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1 + TZ: UTC + THRESHOLD: 0 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET 10 RC + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.100-rc.2.25502.107 + include-prerelease: true + + - name: Install Cosign + uses: sigstore/cosign-installer@v3.4.0 + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: | + ~/.nuget/packages + local-nugets/packages + key: policy-sim-nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} + + - name: Restore CLI + run: | + dotnet restore src/Cli/StellaOps.Cli/StellaOps.Cli.csproj --configfile nuget.config + + - name: Generate policy signing key (ephemeral) + run: | + OUT_DIR=out/policy-sign/keys PREFIX=ci-policy COSIGN_PASSWORD= scripts/policy/rotate-key.sh + + - name: Sign sample policy blob + run: | + export COSIGN_KEY_B64=$(base64 -w0 out/policy-sign/keys/ci-policy-cosign.key) + COSIGN_PASSWORD= \ + scripts/policy/sign-policy.sh --file docs/examples/policies/baseline.stella --out-dir out/policy-sign + + - name: Attest and verify sample policy blob + run: | + export COSIGN_KEY_B64=$(base64 -w0 out/policy-sign/keys/ci-policy-cosign.key) + COSIGN_PASSWORD= \ + scripts/policy/attest-verify.sh --file docs/examples/policies/baseline.stella --out-dir out/policy-sign + + - name: Run batch policy simulation + run: | + scripts/policy/batch-simulate.sh + + - name: Upload simulation artifacts + uses: actions/upload-artifact@v4 + with: + name: policy-simulation + path: out/policy-sim + retention-days: 7 + + - name: Upload signing artifacts + uses: actions/upload-artifact@v4 + with: + name: policy-signing + path: out/policy-sign + retention-days: 7 diff --git a/.gitea/workflows/sdk-publish.yml b/.gitea/workflows/sdk-publish.yml new file mode 100644 index 000000000..1c6c53117 --- /dev/null +++ b/.gitea/workflows/sdk-publish.yml @@ -0,0 +1,89 @@ +name: SDK Publish & Sign + +on: + pull_request: + paths: + - 'src/Sdk/**' + - 'ops/devops/sdk/**' + - 'scripts/sdk/**' + - '.gitea/workflows/sdk-publish.yml' + push: + branches: [ main ] + paths: + - 'src/Sdk/**' + - 'ops/devops/sdk/**' + - 'scripts/sdk/**' + - '.gitea/workflows/sdk-publish.yml' + +jobs: + sdk-publish: + runs-on: ubuntu-22.04 + env: + DOTNET_NOLOGO: 1 + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1 + TZ: UTC + SDK_NUGET_SOURCE: ${{ secrets.SDK_NUGET_SOURCE || 'local-nugets/packages' }} + SDK_NUGET_API_KEY: ${{ secrets.SDK_NUGET_API_KEY }} + SDK_SIGNING_CERT_B64: ${{ secrets.SDK_SIGNING_CERT_B64 }} + SDK_SIGNING_CERT_PASSWORD: ${{ secrets.SDK_SIGNING_CERT_PASSWORD }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET 10 RC + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.100-rc.2.25502.107 + include-prerelease: true + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: | + ~/.nuget/packages + local-nugets/packages + key: sdk-nuget-${{ runner.os }}-${{ hashFiles('src/Sdk/**/*.csproj') }} + + - name: Restore (best effort; skipped if no csproj) + run: | + set -e + if compgen -G "src/Sdk/**/*.csproj" > /dev/null; then + dotnet restore --configfile nuget.config src/Sdk/StellaOps.Sdk.Release/StellaOps.Sdk.Release.csproj || true + else + echo "No SDK csproj present; skipping restore." + fi + + - name: Build & Test (best effort) + run: | + set -e + if compgen -G "src/Sdk/**/*.csproj" > /dev/null; then + dotnet build src/Sdk/StellaOps.Sdk.Release/StellaOps.Sdk.Release.csproj -c Release --no-restore || true + if compgen -G "src/Sdk/**/__Tests/**/*.csproj" > /dev/null; then + dotnet test src/Sdk/**/__Tests/**/*.csproj -c Release --no-build --logger "trx;LogFileName=sdk-tests.trx" || true + fi + else + echo "No SDK csproj present; skipping build/test." + fi + + - name: Sign packages (if present) + run: | + chmod +x scripts/sdk/sign-packages.sh + scripts/sdk/sign-packages.sh + + - name: Publish packages (if present) + run: | + chmod +x scripts/sdk/publish.sh + scripts/sdk/publish.sh + + - name: Upload SDK artifacts + uses: actions/upload-artifact@v4 + with: + name: sdk-artifacts + path: | + out/sdk + local-nugets/packages/*.nupkg + if-no-files-found: warn + retention-days: 7 diff --git a/.gitea/workflows/signals-ci.yml b/.gitea/workflows/signals-ci.yml new file mode 100644 index 000000000..76898b3b3 --- /dev/null +++ b/.gitea/workflows/signals-ci.yml @@ -0,0 +1,72 @@ +name: Signals CI & Image + +on: + pull_request: + paths: + - 'src/Signals/**' + - '.gitea/workflows/signals-ci.yml' + - 'ops/devops/signals/**' + - 'helm/signals/**' + - 'scripts/signals/**' + push: + branches: [ main ] + paths: + - 'src/Signals/**' + - '.gitea/workflows/signals-ci.yml' + - 'ops/devops/signals/**' + - 'helm/signals/**' + - 'scripts/signals/**' + +jobs: + signals-ci: + runs-on: ubuntu-22.04 + env: + DOTNET_NOLOGO: 1 + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1 + TZ: UTC + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET 10 RC + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.100-rc.2.25502.107 + include-prerelease: true + + - name: Cache NuGet packages + uses: actions/cache@v4 + with: + path: | + ~/.nuget/packages + local-nugets/packages + key: signals-nuget-${{ runner.os }}-${{ hashFiles('src/Signals/**/*.csproj') }} + + - name: Restore + run: dotnet restore src/Signals/StellaOps.Signals.sln --configfile nuget.config + + - name: Build + run: dotnet build src/Signals/StellaOps.Signals.sln -c Release --no-restore + + - name: Test + run: dotnet test src/Signals/__Tests/StellaOps.Signals.Tests/StellaOps.Signals.Tests.csproj -c Release --no-build --logger "trx;LogFileName=signals-tests.trx" + + - name: Publish service + run: dotnet publish src/Signals/StellaOps.Signals/StellaOps.Signals.csproj -c Release -o out/signals/publish --no-build + + - name: Build container image + run: | + chmod +x scripts/signals/build.sh + scripts/signals/build.sh + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: signals-offline-kit + path: | + out/signals + out/signals/signals-image.tar + retention-days: 7 diff --git a/docs/api/overview.md b/docs/api/overview.md new file mode 100644 index 000000000..13f5c89ca --- /dev/null +++ b/docs/api/overview.md @@ -0,0 +1,54 @@ +# StellaOps API Overview + +Last updated: 2025-11-25 (Md.V docs stream) + +## Scope +Shared conventions for all StellaOps HTTP APIs. Service-specific schemas live under `src/Api/StellaOps.Api.OpenApi` and composed `out/api/stella.yaml`. + +## Authentication & tenancy +- **Auth**: Bearer tokens (`Authorization: Bearer `); service accounts must include `aud` for the target service. +- **Tenancy**: Multi-tenant endpoints require `X-Stella-Tenant` (or embedded tenant in token claims). Requests without tenant fail with `403` + `error.code = TENANT_REQUIRED`. +- **Scopes**: Each endpoint documents required scopes; clients must send least-privilege tokens. + +## Pagination +- Cursor-based: `page_token` (opaque), `page_size` (default 50, max 500 unless noted). +- Responses include `next_page_token` when more results are available. +- Ordering is deterministic per endpoint (documented under each path). + +## Idempotency +- Write endpoints accept optional `Idempotency-Key` header (UUID). Servers must de-duplicate on key + tenant + path. +- Idempotent methods: GET/HEAD/OPTIONS always; POST/PUT/PATCH/DELETE idempotent only when key is provided and documented. + +## Rate limits +- Standard headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` (UTC epoch seconds). +- 429 responses use the standard error envelope; clients should back off using `Retry-After` when present. + +## Error envelope +All error responses use: +```json +{ + "error": { + "code": "STRING_ENUM", + "message": "human readable", + "trace_id": "" + } +} +``` +- `trace_id` maps to server traces/logs; CLI/Console surface it in verbose output. + +## Headers +- Required observability headers: `traceparent` (W3C), optional `baggage` for routing; services echo correlation IDs in responses. +- Content negotiation: `Accept` defaults to `application/json`; NDJSON endpoints use `application/x-ndjson`. +- All times are UTC ISO-8601; hashes are lowercase hex. + +## Determinism & offline +- APIs must return stable ordering for identical inputs; list endpoints document their sort keys. +- Clients should operate offline using cached responses where supported; air-gap endpoints document required bundles/trust roots. + +## Checklist for new/changed endpoints +- [ ] Added request/response examples (see `examples/` folders). +- [ ] Spectral lint passes (`pnpm api:lint`). +- [ ] Compat report reviewed (`pnpm api:compat` vs `stella-baseline.yaml`). +- [ ] Changelog artefacts generated (`out/api/changelog/*` with checksums/signature). +- [ ] Error envelope and headers documented. +- [ ] Pagination, idempotency, tenancy, scopes documented. diff --git a/docs/api/reference/README.md b/docs/api/reference/README.md new file mode 100644 index 000000000..7a975a125 --- /dev/null +++ b/docs/api/reference/README.md @@ -0,0 +1,40 @@ +# API Reference Site (DOCS-OAS-62-001) + +Last updated: 2025-11-25 + +## Goal +Publish a deterministic, offline-friendly API reference site generated from the consolidated OpenAPI (`out/api/stella.yaml`) and integrate it into the developer portal navigation. + +## Generation steps +1) Build the consolidated spec: + ```bash + pnpm api:build # produces out/api/stella.yaml + pnpm api:lint # optional: spectral lint + pnpm api:compat # optional: compat check vs stella-baseline.yaml + ``` +2) Generate static reference: + ```bash + pnpm api:reference # expected to write to out/api/reference/ + ``` + The command should: + - Use the bundled `out/api/stella.yaml`. + - Produce deterministic HTML/CSS/JS assets (no timestamps in bundles). + - Avoid external CDNs; fonts/assets must be local for air-gap. + +3) Verify determinism/offline: + - Compare hashes of `out/api/reference/` across two runs → must match. + - Open `out/api/reference/index.html` without network access. + +## Portal integration +- Copy `out/api/reference/` into the developer portal static assets under `/reference/`. +- Add nav link “API Reference” pointing to `/reference/`. +- Ensure CSP allows only self-hosted assets (`default-src 'self'`). + +## Artifacts to publish +- `out/api/stella.yaml` (signed checksum). +- `out/api/reference/` (static site; checksum manifest). +- `out/api/reference.sha256` manifest listing all files/hashes. + +## Notes +- Keep OpenAPI examples deterministic (sorted keys, stable ordering). +- Do not embed secrets or environment-specific URLs; use placeholders where needed. diff --git a/docs/api/versioning.md b/docs/api/versioning.md new file mode 100644 index 000000000..70774342d --- /dev/null +++ b/docs/api/versioning.md @@ -0,0 +1,41 @@ +# API Versioning + +Last updated: 2025-11-25 (Docs Tasks Md.V) + +## Principles +- **Semantic versioning**: OpenAPI artifacts follow `MAJOR.MINOR.PATCH` where breaking changes bump MAJOR, additive changes bump MINOR, fixes/docs bump PATCH. +- **Long-lived compatibility**: At least N-1 major versions remain runnable for 12 months; minor versions remain compatible for 6 months after release unless a security fix requires earlier removal. +- **Explicit deprecations**: Every breaking removal/change is preceded by a deprecation window with headers and changelog entries. +- **Deterministic specs**: Generated `out/api/*.yaml` are reproducible from a pinned manifest and committed checksums. + +## How versions are expressed +- **Base URL**: `/api/v{major}/...` (e.g., `/api/v1/policy`). Major only; minor/patch controlled via headers. +- **Headers**: + - `X-Stella-Api-Version: ` → client-requested minor/patch; server chooses the highest compatible available ≤ requested. If omitted, server serves the latest compatible minor/patch for that major. + - `Deprecation: true` + `Sunset: ` returned when an endpoint or field is scheduled for removal. + - `X-Stella-Api-Deprecated-Fields: field1,field2` lists soon-to-be-removed members for the response. +- **Error codes**: + - `error.code = API_VERSION_UNSUPPORTED` when requested major is not served. + - `error.code = API_VERSION_TOO_OLD` when requested minor/patch is below the minimum supported for the major. + +## Compatibility rules +- Additive changes (new fields/enums/paths) are allowed within the same major; fields default to `null`/empty and must not change meaning. +- Breaking changes require a new major: field removals/renames, required field additions, behavior changes that alter contracts. +- Enum extensions: existing values remain; new values must be tolerated by clients. +- Pagination/order: sort keys and determinism must be preserved across versions. + +## Release & lifecycle +1) Draft OpenAPI in `src/Api/StellaOps.Api.OpenApi` and update `out/api/stella.yaml`. +2) Run `pnpm api:lint` + `pnpm api:compat --baseline stella-baseline.yaml` to ensure no unintended breaks. +3) Publish changelog entry under `out/api/changelog/-.md` with checksums/signature. +4) Announce deprecations via release notes; include `Deprecation`/`Sunset` headers in affected endpoints for at least 60 days before removal. +5) Sunset execution: remove endpoints/fields only after the sunset date and after the major bump ships. + +## Client guidance +- Always send `X-Stella-Api-Version` to lock to a tested minor/patch; pin SDK versions accordingly. +- Handle `Deprecation`/`Sunset` headers by warning users and planning upgrades. +- Prefer server-provided pagination tokens; avoid relying on incidental field order. + +## Testing +- Contract tests must cover the lowest and highest supported minor/patch for each major. +- Deterministic fixtures for each version live under `tests/fixtures/api/versioning/`; CI runs `pnpm api:compat` against these fixtures. diff --git a/docs/contributing/api-contracts.md b/docs/contributing/api-contracts.md index 29f9d503c..c5b598e54 100644 --- a/docs/contributing/api-contracts.md +++ b/docs/contributing/api-contracts.md @@ -1,37 +1,58 @@ -# API Contract Contribution Guide +# Contributing to API Contracts -This guide explains how to propose, review, and publish API contract changes across StellaOps services. Follow these steps whenever you modify an OpenAPI specification or an externally supported endpoint. +Last updated: 2025-11-25 -## 1. Background +## Scope +Guidelines for editing service OpenAPI specs, lint rules, compatibility checks, and release artefacts across StellaOps services. -- Public APIs are defined in `src/Api/StellaOps.Api.OpenApi` (aggregate spec) and per-service OpenAPI documents. -- Compatibility checks run in CI via the API Governance tooling (`StellaOps.Api.Governance`). -- Docs & SDK guilds consume the generated specs to publish references and SDK packages. +## Required tools +- Node.js 20.x + pnpm 9.x +- Spectral CLI (invoked via `pnpm api:lint` in `src/Api/StellaOps.Api.OpenApi`) +- `diff2html` (optional) for human-friendly compat reports -## 2. Workflow +## Workflow (per change) +1) Edit service OAS under `src/Api/StellaOps.Api.OpenApi/services//*.yaml`. +2) Run lint + compose + compat + changelog from repo root: + ```bash + pnpm --filter @stella/api-openapi api:lint # spectral + pnpm --filter @stella/api-openapi api:compose # build stella.yaml + pnpm --filter @stella/api-openapi api:compat # compare against baseline + pnpm --filter @stella/api-openapi api:changelog # generate digest/signature + ``` +3) Review outputs: + - `out/api/stella.yaml` (composed spec) + - `out/api/compat-report.json` (+ `.html` if generated) + - `out/api/changelog/` (digest + signature for SDK pipeline) +4) Update examples: ensure request/response examples exist for changed endpoints; add to `examples/` directories. +5) Commit changes with notes on breaking/additive results; attach compat report paths. -1. **Design review** – capture the proposed endpoint or schema change in the relevant module’s `TASKS.md` and link to any ADR or design doc. -2. **Spec update** – modify the service-specific OpenAPI file under `src/Api/StellaOps.Api.OpenApi//`. -3. **Run governance checks** – execute `dotnet test src/Api/StellaOps.Api.Governance.Tests` to validate lint rules, backwards compatibility, and examples. -4. **Regenerate aggregate spec** – run `dotnet run --project src/Api/StellaOps.Api.OpenApi` to update `stella.yaml`. -5. **Update docs** – adjust the corresponding module dossier (`docs/modules//architecture.md` or guides) to reflect new/changed endpoints. -6. **Notify SDK/Docs guilds** – coordinate SDK regeneration (`src/Sdk/StellaOps.Sdk.Generator`) and release notes. +## Lint rules (Spectral) +- House rules live in `.spectral.yaml` under `src/Api/StellaOps.Api.OpenApi`. +- Enforce: tagged operations, error envelope shape, schema refs reuse, pagination tokens, RBAC scopes, standard headers (`traceparent`, `x-correlation-id`). -## 3. Backwards Compatibility Rules +## Compatibility checks +- Baseline file: `stella-baseline.yaml` (kept in repo under `out/api/` and updated per release). +- `api:compat` flags additive/breaking/unchanged deltas. Breaking changes require approval from API Governance Guild and affected service guilds. -- Avoid breaking changes (removing endpoints/fields, altering semantics). If unavoidable, document deprecation timelines and fallback behaviour. -- Additive changes (new optional fields, new endpoints) require version bump and changelog entry. -- Error responses must remain structured; return `application/problem+json` payloads with stable error codes. +## Examples & error envelopes +- Every operation must have at least one request + response example. +- Error responses must use the standard envelope (`error.code`, `error.message`, `trace_id`). -## 4. Tooling +## Offline/air-gap +- Keep `pnpm-lock.yaml` pinned; store `node_modules/.pnpm` cache in Offline Kit when needed. +- Include composed spec, compat report, and changelog artefacts in offline bundles under `offline/api/` with checksums. -- `dotnet tool run stellaops-api-lint` – local lint. -- `dotnet run --project src/Api/StellaOps.Api.OpenApi -- --validate` – schema validation. -- `docs/09_API_CLI_REFERENCE.md` – update CLI reference when command behaviour shifts. +## Release handoff +- Deliverables for each release: + - `out/api/stella.yaml` + - `out/api/compat-report.json` (+ `.html` if produced) + - `out/api/changelog/*` (digest, signature, manifest) +- Provide SHA256 checksums for artefacts and note `source_commit` + `timestamp` in release notes. -## 5. References - -- `docs/modules/platform/architecture-overview.md` -- `docs/modules/cli/architecture.md` -- `src/Api/StellaOps.Api.Governance` -- `src/Api/StellaOps.Api.OpenApi` +## Review checklist +- [ ] Lint clean (`api:lint`) +- [ ] Examples present for changed endpoints +- [ ] Compat report reviewed (additive/breaking noted) +- [ ] Changelog artefacts generated + checksums +- [ ] Offline bundle artefacts staged (if required) +- [ ] Docs/UI/SDK owners notified of breaking changes diff --git a/docs/examples/policies/sample-sbom.json b/docs/examples/policies/sample-sbom.json new file mode 100644 index 000000000..e675c38b7 --- /dev/null +++ b/docs/examples/policies/sample-sbom.json @@ -0,0 +1,19 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "components": [ + { + "type": "library", + "name": "demo-lib", + "version": "1.0.0", + "purl": "pkg:npm/demo-lib@1.0.0" + }, + { + "type": "library", + "name": "lodash", + "version": "4.17.21", + "purl": "pkg:npm/lodash@4.17.21" + } + ] +} diff --git a/docs/implplan/SPRINT_0114_0001_0003_concelier_iii.md b/docs/implplan/SPRINT_0114_0001_0003_concelier_iii.md index 0d621f907..7b6e1fe56 100644 --- a/docs/implplan/SPRINT_0114_0001_0003_concelier_iii.md +++ b/docs/implplan/SPRINT_0114_0001_0003_concelier_iii.md @@ -20,6 +20,7 @@ ## Delivery Tracker | # | Task ID | Status | Key dependency / next step | Owners | Task Definition | | --- | --- | --- | --- | --- | --- | +| 0 | OPS-CLEAN-DISK-001 | BLOCKED (2025-11-25) | Free disk space on dev runner (`bin/obj`, TestResults, ops/devops/artifacts/ci-110) to allow builds/tests. | DevOps | Clear workspace storage so orchestrator WebService tests can run. | | 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. | @@ -34,17 +35,19 @@ | 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 | BLOCKED (2025-11-25) | CI build still fails locally (Aoc.AspNetCore dependency) and orchestrator WebService tests missing; requires clean CI runner (DEVOPS-CONCELIER-CI-24-101) to validate. | 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 | BLOCKED (2025-11-25) | Blocked on 32-001 CI/build + missing orchestrator WebService tests. | 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 | BLOCKED (2025-11-25) | Blocked by 32-001/32-002 validation and CI availability. | 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 | BLOCKED (2025-11-25) | Blocked until 32-002/33-001 validated on CI; backfill tests pending. | 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. | +| 10 | CONCELIER-ORCH-32-001 | BLOCKED (2025-11-25) | CI build + orchestrator WebService tests blocked by disk-full runner; need clean space/CI (DEVOPS-CONCELIER-CI-24-101) to validate. | 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 | BLOCKED (2025-11-25) | Blocked on 32-001 and disk exhaustion preventing test runs. | 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 | BLOCKED (2025-11-25) | Blocked by 32-001/32-002 validation and disk-full test runner. | 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 | BLOCKED (2025-11-25) | Blocked until 32-002/33-001 validated; test runner out of disk space. | 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 | DONE (2025-11-25) | Linkset APIs now enrich severity and published/modified timeline using raw observations; CPEs, conflicts, and provenance hashes exposed. | 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 | | --- | --- | --- | +| 2025-11-25 | Runner disk is full (“No space left on device”); orchestrator WebService tests cannot be re-run. Free bin/obj/TestResults and `ops/devops/artifacts/ci-110` before continuing ORCH-32/33/34. | Concelier Core | | 2025-11-25 | Storage.Mongo job-store slice executed locally: `dotnet test src/Concelier/__Tests/StellaOps.Concelier.Storage.Mongo.Tests/StellaOps.Concelier.Storage.Mongo.Tests.csproj -c Debug --no-restore --no-build --filter FullyQualifiedName~MongoJobStore` (3/3 pass). TRX: `ops/devops/artifacts/ci-110/20251125T034529Z/trx/concelier-storage-jobstore.trx`. Broader suite still pending CI. | Concelier Core | | 2025-11-25 | WebService orchestrator filter run (`dotnet test ...WebService.Tests.csproj --filter FullyQualifiedName~Orchestrator`) produced no matching tests; TRX recorded at `ops/devops/artifacts/ci-110/20251125T040900Z/trx/concelier-web-orch.trx`. Need to add orchestrator WebService tests before closing ORCH-32/33/34. | Concelier Core | +| 2025-11-25 | Attempted to add WebService orchestrator tests with Mongo bypass; repo disk is full (`No space left on device`), preventing further builds/tests. Cleanup of bin/obj/TestResults and ops/devops artifacts required before rerunning orchestrator test slice. | Concelier Core | | 2025-11-25 | Added observation-backed severity/published/modified projection to `/v1/lnm/linksets*`; updated integration test to assert timeline/published fields. POLICY-20-001 closed. | Implementer | | 2025-11-25 | Marked CONCELIER-ORCH-32/33/34 chain BLOCKED: local build fails on Aoc.AspNetCore dependency and orchestrator WebService tests are absent; needs CI runner DEVOPS-CONCELIER-CI-24-101 and new tests before proceeding. | Implementer | | 2025-11-25 | Targeted orchestrator tests (Storage.Mongo) succeeded previously with filter `--filter Orchestrator` but full suite still hangs; CI runner needed for full coverage. | Concelier Core | @@ -88,6 +91,7 @@ | 2025-11-24 | Marked CONCELIER-POLICY-20-001 BLOCKED: upstream linkset/ingest lacks authoritative severity data and published/modified timestamps; cannot emit full severity/timeline fields until schema and data are supplied. | Concelier Core | ## Decisions & Risks +- Disk space on the dev runner is exhausted (`No space left on device`), blocking `dotnet test` for orchestrator endpoints; free `src/Concelier/**/bin|obj`, stale TestResults, and `ops/devops/artifacts/ci-110` before rerunning ORCH-32/33/34. - Link-Not-Merge and OpenAPI alignment must precede SDK/examples; otherwise downstream clients will drift from canonical facts. - Observability/attestation chain (OBS-51…55) risks audit gaps if sequencing slips; each step depends on previous artifacts. - Orchestrator control compliance is required to prevent evidence loss during throttles/pauses. @@ -105,6 +109,7 @@ - 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. - Build remains blocked by CS8620 nullable mismatch in `LinksetCorrelation.cs` (linkset aggregation); patch applied but nullability config appears to treat warning as error—needs follow-up to clear WebService build. - ORCH-32/33/34 implementation blocked locally by missing package restore/nullability errors; CI or clean runner required to validate before proceeding with worker SDK wiring. +- Disk space exhausted on dev runner, preventing further test/build execution; must clear `src/Concelier/**/bin|obj`, stale TestResults, and `ops/devops/artifacts/ci-110` before rerunning ORCH test slice. ## Next Checkpoints - Schedule OpenAPI/SDK review once CONCELIER-OAS-61-001 draft ready (date TBD, gated on Sprint 0113 outputs). diff --git a/docs/implplan/SPRINT_0119_0001_0005_excititor_v.md b/docs/implplan/SPRINT_0119_0001_0005_excititor_v.md index e61c8eeee..944593cc8 100644 --- a/docs/implplan/SPRINT_0119_0001_0005_excititor_v.md +++ b/docs/implplan/SPRINT_0119_0001_0005_excititor_v.md @@ -21,14 +21,14 @@ ## Delivery Tracker | # | Task ID | Status | Key dependency / next step | Owners | Task Definition | | --- | --- | --- | --- | --- | --- | -| 1 | EXCITITOR-VEXLENS-30-001 | TODO | Align required enrichers/fields with VEX Lens. | Excititor WebService Guild · VEX Lens Guild | Ensure observations exported to VEX Lens carry issuer hints, signature blobs, product tree snippets, staleness metadata; no consensus logic. | +| 1 | EXCITITOR-VEXLENS-30-001 | BLOCKED (2025-11-25) | Await VEX Lens field list / examples. | Excititor WebService Guild · VEX Lens Guild | Ensure observations exported to VEX Lens carry issuer hints, signature blobs, product tree snippets, staleness metadata; no consensus logic. | | 2 | EXCITITOR-VULN-29-001 | BLOCKED (2025-11-23) | Missing `advisory_key` canonicalization spec from Vuln Explorer; cannot design backfill. | Excititor WebService Guild | Canonicalize advisory/product keys to `advisory_key`, capture scope metadata, preserve originals in `links[]`; backfill + tests. | | 3 | EXCITITOR-VULN-29-002 | BLOCKED (2025-11-23) | Blocked on 29-001 canonicalization contract. | Excititor WebService Guild | `/vuln/evidence/vex/{advisory_key}` returning tenant-scoped raw statements, provenance, attestation references for Vuln Explorer. | | 4 | EXCITITOR-VULN-29-004 | BLOCKED (2025-11-23) | Blocked on 29-002 endpoint shape. | Excititor WebService · Observability Guild | Metrics/logs for normalization errors, suppression scopes, withdrawn statements for Vuln Explorer + Advisory AI dashboards. | -| 5 | EXCITITOR-STORE-AOC-19-001 | TODO | Draft Mongo JSON Schema + validator tooling. | Excititor Storage Guild | Ship validator (incl. Offline Kit instructions) proving Excititor stores only immutable evidence. | -| 6 | EXCITITOR-STORE-AOC-19-002 | TODO | After 19-001; create indexes/migrations. | Excititor Storage · DevOps Guild | Unique indexes, migrations/backfills, rollback steps for new validator. | -| 7 | EXCITITOR-AIRGAP-56-001 | TODO | Define mirror registration envelope. | Excititor WebService Guild | Mirror bundle registration + provenance exposure, sealed-mode error mapping, staleness metrics in API responses. | -| 8 | EXCITITOR-AIRGAP-58-001 | TODO | Depends on 56-001 + bundle schema. | Excititor Core · Evidence Locker Guild | Portable evidence bundles linked to timeline + attestation metadata; document verifier steps for Advisory AI. | +| 5 | EXCITITOR-STORE-AOC-19-001 | DONE (2025-11-25) | Draft Mongo JSON Schema + validator tooling. | Excititor Storage Guild | Ship validator (incl. Offline Kit instructions) proving Excititor stores only immutable evidence. | +| 6 | EXCITITOR-STORE-AOC-19-002 | DONE (2025-11-25) | After 19-001; create indexes/migrations. | Excititor Storage · DevOps Guild | Unique indexes, migrations/backfills, rollback steps for new validator. | +| 7 | EXCITITOR-AIRGAP-56-001 | BLOCKED (2025-11-25) | Mirror registration contract/schema not published. | Excititor WebService Guild | Mirror bundle registration + provenance exposure, sealed-mode error mapping, staleness metrics in API responses. | +| 8 | EXCITITOR-AIRGAP-58-001 | BLOCKED (2025-11-25) | Depends on 56-001 + bundle schema. | Excititor Core · Evidence Locker Guild | Portable evidence bundles linked to timeline + attestation metadata; document verifier steps for Advisory AI. | ## Action Tracker | Focus | Action | Owner(s) | Due | Status | @@ -44,11 +44,14 @@ | --- | --- | --- | | 2025-11-16 | Normalized sprint file to standard template and renamed to SPRINT_0119_0001_0005_excititor_v.md; awaiting execution. | Planning | | 2025-11-23 | Marked Vuln Explorer chain (29-001/002/004) BLOCKED pending `advisory_key` canonicalization spec from Vuln Explorer; Action Tracker updated. | Project Mgmt | +| 2025-11-25 | Added `$jsonSchema` validator migration (`20251125-vex-raw-json-schema`) plus schema doc and rollback/runbook; marked EXCITITOR-STORE-AOC-19-001/002 DONE. | Implementer | +| 2025-11-25 | Marked VEX Lens export (30-001) BLOCKED awaiting Lens field list; set AirGap 56-001/58-001 BLOCKED until mirror registration + bundle schema arrive. | Project Mgmt | ## Decisions & Risks - **Decisions** - Keep all exports/APIs aggregation-only; consensus remains outside Excititor. - Portable bundles must include timeline + attestation references without Excititor interpretation. + - Raw collection validation ships in warn mode; can be promoted to error once datasets are clean. - **Risks & Mitigations** - Validator rollout could impact live ingestion → Staged rollout with dry-run validator and rollback steps. - Mirror bundle schema delays impact bundles → Use placeholder manifest with TODOs and track deltas until schema lands. diff --git a/docs/implplan/SPRINT_0119_0001_0006_excititor_vi.md b/docs/implplan/SPRINT_0119_0001_0006_excititor_vi.md index 4397c5d3a..735331084 100644 --- a/docs/implplan/SPRINT_0119_0001_0006_excititor_vi.md +++ b/docs/implplan/SPRINT_0119_0001_0006_excititor_vi.md @@ -32,10 +32,10 @@ | Focus | Action | Owner(s) | Due | Status | | --- | --- | --- | --- | --- | | Streaming APIs | Finalize SSE/WebSocket contract + guardrails (WEB-OBS-52-001). | WebService Guild | 2025-11-20 | DONE (2025-11-24) | -| Evidence/Attestation APIs | Wire endpoints + verification metadata (WEB-OBS-53/54). | WebService · Evidence Locker Guild | 2025-11-22 | TODO | +| Evidence/Attestation APIs | Wire endpoints + verification metadata (WEB-OBS-53/54). | WebService · Evidence Locker Guild | 2025-11-22 | BLOCKED | | OpenAPI discovery | Implement well-known discovery + examples (WEB-OAS-61/62). | WebService · API Gov | 2025-11-21 | DONE (61-001, 62-001 delivered 2025-11-24) | -| Bundle telemetry | Define audit event + sealed-mode remediation mapping (WEB-AIRGAP-58-001). | WebService · AirGap Guilds | 2025-11-23 | TODO | -| Crypto providers | Design `ICryptoProviderRegistry` and migrate call sites (CRYPTO-90-001). | WebService · Security Guild | 2025-11-24 | TODO | +| Bundle telemetry | Define audit event + sealed-mode remediation mapping (WEB-AIRGAP-58-001). | WebService · AirGap Guilds | 2025-11-23 | BLOCKED | +| Crypto providers | Design `ICryptoProviderRegistry` and migrate call sites (CRYPTO-90-001). | WebService · Security Guild | 2025-11-24 | BLOCKED | ## Execution Log | Date (UTC) | Update | Owner | @@ -46,6 +46,8 @@ | 2025-11-24 | Enriched `/openapi/excititor.json` with concrete paths (status, health, timeline SSE, airgap import) plus response/examples and deprecation/link headers on timeline SSE; EXCITITOR-WEB-OAS-62-001 remains DOING pending legacy route deprecation headers + SDK docs. | Implementer | | 2025-11-24 | Added response examples (status/health), error examples (timeline 400, airgap 400/403), and documented deprecation/link headers in OpenAPI spec; marked EXCITITOR-WEB-OAS-62-001 DONE. SDK doc publish tracked separately. | Implementer | | 2025-11-24 | Implemented `/obs/excititor/timeline` SSE endpoint (cursor + Last-Event-ID, retry header, tenant guard). Marked EXCITITOR-WEB-OBS-52-001 DONE and streaming action tracker item done. | Implementer | +| 2025-11-25 | Work paused: build/CI commands blocked (`No space left on device`); further coding waits on workspace cleanup. | Implementer | +| 2025-11-25 | Marked action tracker items for evidence/attestation APIs, bundle telemetry, and crypto providers as BLOCKED to mirror Delivery Tracker; upstream Evidence Locker bundle schema and crypto registry spec still missing. | Implementer | ## Decisions & Risks - **Decisions** diff --git a/docs/implplan/SPRINT_0129_0001_0001_policy_reasoning.md b/docs/implplan/SPRINT_0129_0001_0001_policy_reasoning.md index f4584b5b7..82e53fd2a 100644 --- a/docs/implplan/SPRINT_0129_0001_0001_policy_reasoning.md +++ b/docs/implplan/SPRINT_0129_0001_0001_policy_reasoning.md @@ -17,24 +17,24 @@ ## Delivery Tracker | # | Task ID & handle | State | Key dependency / next step | Owners | Task Definition | | --- | --- | --- | --- | --- | --- | -| 1 | POLICY-TEN-48-001 | TODO | Tenant/project columns + RLS policy; needs platform-approved design. | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Tenant scoping + rationale IDs with tenant metadata. | -| 2 | REGISTRY-API-27-001 | TODO | OpenAPI spec pending. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Define Registry API spec + typed clients. | -| 3 | REGISTRY-API-27-002 | TODO | Depends on 27-001. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Workspace storage with CRUD + history. | -| 4 | REGISTRY-API-27-003 | TODO | Depends on 27-002. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Compile endpoint integration. | -| 5 | REGISTRY-API-27-004 | TODO | Depends on 27-003. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Quick simulation API. | -| 6 | REGISTRY-API-27-005 | TODO | Depends on 27-004. | Policy Registry · Scheduler Guild / `src/Policy/StellaOps.Policy.Registry` | Batch simulation orchestration. | -| 7 | REGISTRY-API-27-006 | TODO | Depends on 27-005. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Review workflow with audit trails. | -| 8 | REGISTRY-API-27-007 | TODO | Depends on 27-006. | Policy Registry · Security Guild / `src/Policy/StellaOps.Policy.Registry` | Publish pipeline with signing/attestations. | -| 9 | REGISTRY-API-27-008 | TODO | Depends on 27-007. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Promotion bindings per tenant/environment. | -| 10 | REGISTRY-API-27-009 | TODO | Depends on 27-008. | Policy Registry · Observability Guild / `src/Policy/StellaOps.Policy.Registry` | Metrics/logs/traces + dashboards. | -| 11 | REGISTRY-API-27-010 | TODO | Depends on 27-009. | Policy Registry · QA Guild / `src/Policy/StellaOps.Policy.Registry` | Test suites + fixtures. | +| 1 | POLICY-TEN-48-001 | BLOCKED | Tenant/project columns + RLS policy; needs platform-approved design. | Policy Guild / `src/Policy/StellaOps.Policy.Engine` | Tenant scoping + rationale IDs with tenant metadata. | +| 2 | REGISTRY-API-27-001 | BLOCKED | OpenAPI spec pending. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Define Registry API spec + typed clients. | +| 3 | REGISTRY-API-27-002 | BLOCKED | Depends on 27-001. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Workspace storage with CRUD + history. | +| 4 | REGISTRY-API-27-003 | BLOCKED | Depends on 27-002. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Compile endpoint integration. | +| 5 | REGISTRY-API-27-004 | BLOCKED | Depends on 27-003. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Quick simulation API. | +| 6 | REGISTRY-API-27-005 | BLOCKED | Depends on 27-004. | Policy Registry · Scheduler Guild / `src/Policy/StellaOps.Policy.Registry` | Batch simulation orchestration. | +| 7 | REGISTRY-API-27-006 | BLOCKED | Depends on 27-005. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Review workflow with audit trails. | +| 8 | REGISTRY-API-27-007 | BLOCKED | Depends on 27-006. | Policy Registry · Security Guild / `src/Policy/StellaOps.Policy.Registry` | Publish pipeline with signing/attestations. | +| 9 | REGISTRY-API-27-008 | BLOCKED | Depends on 27-007. | Policy Registry Guild / `src/Policy/StellaOps.Policy.Registry` | Promotion bindings per tenant/environment. | +| 10 | REGISTRY-API-27-009 | BLOCKED | Depends on 27-008. | Policy Registry · Observability Guild / `src/Policy/StellaOps.Policy.Registry` | Metrics/logs/traces + dashboards. | +| 11 | REGISTRY-API-27-010 | BLOCKED | Depends on 27-009. | Policy Registry · QA Guild / `src/Policy/StellaOps.Policy.Registry` | Test suites + fixtures. | | 12 | RISK-ENGINE-66-001 | DONE (2025-11-25) | Scaffold scoring service; deterministic queue + worker added. | Risk Engine Guild / `src/RiskEngine/StellaOps.RiskEngine` | Scoring service + job queue + provider registry with deterministic harness. | | 13 | RISK-ENGINE-66-002 | DONE (2025-11-25) | Depends on 66-001. | Risk Engine Guild / `src/RiskEngine/StellaOps.RiskEngine` | Default transforms/clamping/gating. | | 14 | RISK-ENGINE-67-001 | DONE (2025-11-25) | Depends on 66-002. | Risk Engine Guild · Concelier Guild / `src/RiskEngine/StellaOps.RiskEngine` | CVSS/KEV providers. | | 15 | RISK-ENGINE-67-002 | DONE (2025-11-25) | Depends on 67-001. | Risk Engine Guild · Excitor Guild / `src/RiskEngine/StellaOps.RiskEngine` | VEX gate provider. | | 16 | RISK-ENGINE-67-003 | DONE (2025-11-25) | Depends on 67-002. | Risk Engine Guild · Policy Engine Guild / `src/RiskEngine/StellaOps.RiskEngine` | Fix availability/criticality/exposure providers. | | 17 | RISK-ENGINE-68-001 | DONE (2025-11-25) | Depends on 67-003. | Risk Engine Guild · Findings Ledger Guild / `src/RiskEngine/StellaOps.RiskEngine` | Persist results + explanations to Findings Ledger. | -| 18 | RISK-ENGINE-68-002 | TODO | Depends on 68-001. | Risk Engine Guild / `src/RiskEngine/StellaOps.RiskEngine` | APIs for jobs/results/simulations. | +| 18 | RISK-ENGINE-68-002 | DONE (2025-11-25) | Depends on 68-001. | Risk Engine Guild / `src/RiskEngine/StellaOps.RiskEngine` | APIs for jobs/results/simulations. | | 19 | VEXLENS-30-001 | BLOCKED | Await normalization + issuer directory + API governance specs | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Normalize CSAF/OpenVEX/CycloneDX VEX. | | 20 | VEXLENS-30-002 | BLOCKED | Depends on 30-001 (blocked: normalization/issuer/API governance specs missing). | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Product mapping library. | | 21 | VEXLENS-30-003 | BLOCKED | Depends on 30-002 (blocked). | VEX Lens Guild · Issuer Directory Guild / `src/VexLens/StellaOps.VexLens` | Signature verification. | @@ -46,29 +46,38 @@ | 27 | VEXLENS-30-009 | BLOCKED | Depends on 30-008 (blocked). | VEX Lens · Observability Guild / `src/VexLens/StellaOps.VexLens` | Metrics/logs/traces. | | 28 | VEXLENS-30-010 | BLOCKED | Depends on 30-009 (blocked). | VEX Lens · QA Guild / `src/VexLens/StellaOps.VexLens` | Tests + determinism harness. | | 29 | VEXLENS-30-011 | BLOCKED | Depends on 30-010 (blocked). | VEX Lens · DevOps Guild / `src/VexLens/StellaOps.VexLens` | Deployment/runbooks/offline kit. | -| 30 | VEXLENS-AIAI-31-001 | TODO | Depends on 30-011. | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Consensus rationale API enhancements. | -| 31 | VEXLENS-AIAI-31-002 | TODO | Depends on AIAI-31-001. | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Caching hooks for Advisory AI. | -| 32 | VEXLENS-EXPORT-35-001 | TODO | Depends on 30-011. | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Consensus snapshot API for mirror bundles. | -| 33 | VEXLENS-ORCH-33-001 | TODO | Depends on 30-011. | VEX Lens · Orchestrator Guild / `src/VexLens/StellaOps.VexLens` | Register consensus compute job type. | -| 34 | VEXLENS-ORCH-34-001 | TODO | Depends on ORCH-33-001. | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Emit consensus completion events to orchestrator ledger. | +| 30 | VEXLENS-AIAI-31-001 | BLOCKED | Depends on 30-011. | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Consensus rationale API enhancements. | +| 31 | VEXLENS-AIAI-31-002 | BLOCKED | Depends on AIAI-31-001. | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Caching hooks for Advisory AI. | +| 32 | VEXLENS-EXPORT-35-001 | BLOCKED | Depends on 30-011. | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Consensus snapshot API for mirror bundles. | +| 33 | VEXLENS-ORCH-33-001 | BLOCKED | Depends on 30-011. | VEX Lens · Orchestrator Guild / `src/VexLens/StellaOps.VexLens` | Register consensus compute job type. | +| 34 | VEXLENS-ORCH-34-001 | BLOCKED | Depends on ORCH-33-001. | VEX Lens Guild / `src/VexLens/StellaOps.VexLens` | Emit consensus completion events to orchestrator ledger. | | 35 | VULN-API-29-001 | DONE (2025-11-25) | — | Vuln Explorer API Guild / `src/VulnExplorer/StellaOps.VulnExplorer.Api` | Define VulnExplorer OpenAPI spec. | -| 36 | VULN-API-29-002 | TODO | Depends on 29-001. | Vuln Explorer API Guild / `src/VulnExplorer/StellaOps.VulnExplorer.Api` | Implement list/query endpoints. | +| 36 | VULN-API-29-002 | DONE (2025-11-25) | Depends on 29-001. | Vuln Explorer API Guild / `src/VulnExplorer/StellaOps.VulnExplorer.Api` | Implement list/query endpoints + Swagger stub; tests at `tests/TestResults/vuln-explorer/api.trx`. | +| 37 | VULN-API-29-003 | DONE (2025-11-25) | Depends on 29-002. | Vuln Explorer API Guild / `src/VulnExplorer/StellaOps.VulnExplorer.Api` | Detail endpoint with evidence, rationale, paths; covered by integration tests. | ## Execution Log | Date (UTC) | Update | Owner | | --- | --- | --- | +| 2025-11-25 | Marked VEXLENS-AIAI-31-001/002, VEXLENS-EXPORT-35-001, VEXLENS-ORCH-33-001, and VEXLENS-ORCH-34-001 BLOCKED; consensus chain (30-011) remains blocked upstream. | Project Mgmt | | 2025-11-25 | RISK-ENGINE-67-002 DONE: VEX gate provider added with short-circuit tests; packaged in RiskEngine queue/worker pipeline. | Implementer | | 2025-11-25 | RISK-ENGINE-67-001 DONE: added CVSS+KEV provider and tests; score formula clamp((cvss/10)+0.2 if KEV). | Implementer | | 2025-11-25 | RISK-ENGINE-68-001 DONE: risk score worker now persists results via result store abstraction; in-memory store added plus persistence tests; TRX at `TestResults/risk-engine/risk.trx`. | Implementer | | 2025-11-25 | RISK-ENGINE-67-003 DONE: fix-availability/criticality/exposure provider added with missing-signal default tests; TRX at `TestResults/risk-engine/risk.trx`. | Implementer | +| 2025-11-25 | RISK-ENGINE-68-002 DONE: exposed provider list, job submit/retrieve, and batch simulation APIs; in-memory result store wired; integration tests green at `TestResults/risk-engine/api.trx`. | Implementer | +| 2025-11-25 | RISK-ENGINE-68-002: simulation summary rounding clarified (avg rounded to 6 decimals); refreshed integration tests at `TestResults/risk-engine/api.trx`. | Implementer | | 2025-11-25 | VULN-API-29-001 DONE: drafted OpenAPI spec at `docs/modules/vuln-explorer/openapi/vuln-explorer.v1.yaml` and summary `docs/modules/vuln-explorer/api.md`; includes tenant header, filters, deterministic paging. | Implementer | +| 2025-11-25 | VULN-API-29-002 DONE: Minimal API list/detail implemented with deterministic paging, sample data, Swagger UI; integration tests green (`tests/TestResults/vuln-explorer/api.trx`). | Implementer | +| 2025-11-25 | VULN-API-29-003 DONE: Detail endpoint now returns rationale, paths, evidence refs; tests updated (`tests/TestResults/vuln-explorer/api.trx`). | Implementer | +| 2025-11-25 | Synced Vuln Explorer `TASKS.md` with sprint statuses for VULN-API-29-001/002/003. | Implementer | | 2025-11-25 | RISK-ENGINE-66-002 DONE: added default-transforms provider (clamp [0,1] then average), queue/worker tests updated; TRX at `TestResults/risk-engine/risk.trx`. | Implementer | | 2025-11-25 | RISK-ENGINE-66-001 DONE: scaffolded deterministic risk score queue + worker + provider registry; added unit tests verifying FIFO ordering and missing-provider failures. | Implementer | | 2025-11-25 | Marked VEXLENS-30-002..30-011 BLOCKED because upstream VEXLENS-30-001 remains blocked on normalization schema + issuer directory + API governance specs; mirrored to tasks-all. | Project Mgmt | | 2025-11-25 | Marked VEXLENS-30-001 BLOCKED pending normalization schema, issuer directory inputs, and API governance guidance; downstream VEXLENS tasks remain TODO and depend on this. | Project Mgmt | | 2025-11-25 | Removed legacy `SPRINT_129_policy_reasoning.md`, pointed trackers to canonical name, and created `src/VexLens/StellaOps.VexLens/TASKS.md` mirroring VEX Lens tasks; statuses remain TODO pending upstream specs. | Project Mgmt | +| 2025-11-25 | Marked REGISTRY-API-27-001..010 and POLICY-TEN-48-001 BLOCKED; Registry/OpenAPI and tenancy design inputs are absent, so downstream registry work cannot start. | Implementer | | 2025-11-08 | Sprint stub; awaiting upstream specs. | Planning | | 2025-11-19 | Normalized to standard template and renamed from `SPRINT_129_policy_reasoning.md` to `SPRINT_0129_0001_0001_policy_reasoning.md`; content preserved. | Implementer | +| 2025-11-25 | Work paused: repository cannot allocate PTY (`No space left on device`); further execution awaits workspace cleanup. | Implementer | ## Decisions & Risks - Multiple upstream specs missing (Registry API, Risk Engine contracts, VEX consensus schema, issuer directory, API governance, VulnExplorer API); VEXLENS-30-001 blocked until normalization + issuer inputs land; downstream tasks depend on it. diff --git a/docs/implplan/SPRINT_0510_0001_0001_airgap.md b/docs/implplan/SPRINT_0510_0001_0001_airgap.md index 1aa5c74bc..16c20702a 100644 --- a/docs/implplan/SPRINT_0510_0001_0001_airgap.md +++ b/docs/implplan/SPRINT_0510_0001_0001_airgap.md @@ -27,11 +27,11 @@ | P7 | PREP-AIRGAP-IMP-56-002-BLOCKED-ON-56-001 | DONE (2025-11-20) | Due 2025-11-26 · Accountable: AirGap Importer Guild · Security Guild | AirGap Importer Guild · Security Guild | Blocked on 56-001.

Deliverable shares scaffold above; downstream tasks now have deterministic plan and trust-root contract. | | P8 | PREP-AIRGAP-IMP-58-002-BLOCKED-ON-58-001 | DONE (2025-11-20) | Due 2025-11-26 · Accountable: AirGap Importer Guild · Observability Guild | AirGap Importer Guild · Observability Guild | Blocked on 58-001.

Deliverable shares scaffold above; includes plan steps + validation envelope for import timeline events. | | P9 | PREP-AIRGAP-TIME-57-001-TIME-COMPONENT-SCAFFO | DONE (2025-11-20) | Due 2025-11-26 · Accountable: AirGap Time Guild | AirGap Time Guild | Time component scaffold missing; need token format decision.

Deliverable: `src/AirGap/StellaOps.AirGap.Time` project + tests and doc `docs/airgap/time-anchor-scaffold.md` covering Roughtime/RFC3161 stub parser. | -| 1 | AIRGAP-CTL-56-001 | BLOCKED | PREP-AIRGAP-CTL-56-001-CONTROLLER-PROJECT-SCA | AirGap Controller Guild | Implement `airgap_state` persistence, seal/unseal state machine, and Authority scope checks (`airgap:seal`, `airgap:status:read`). | -| 2 | AIRGAP-CTL-56-002 | BLOCKED | PREP-AIRGAP-CTL-56-002-BLOCKED-ON-56-001-SCAF | AirGap Controller Guild · DevOps Guild | Expose `GET /system/airgap/status`, `POST /system/airgap/seal`, integrate policy hash validation, and return staleness/time anchor placeholders. | -| 3 | AIRGAP-CTL-57-001 | BLOCKED | PREP-AIRGAP-CTL-57-001-BLOCKED-ON-56-002 | AirGap Controller Guild | Add startup diagnostics that block application run when sealed flag set but egress policies missing; emit audit + telemetry. | -| 4 | AIRGAP-CTL-57-002 | BLOCKED | PREP-AIRGAP-CTL-57-002-BLOCKED-ON-57-001 | AirGap Controller Guild · Observability Guild | Instrument seal/unseal events with trace/log fields and timeline emission (`airgap.sealed`, `airgap.unsealed`). | -| 5 | AIRGAP-CTL-58-001 | BLOCKED | PREP-AIRGAP-CTL-58-001-BLOCKED-ON-57-002 | AirGap Controller Guild · AirGap Time Guild | Persist time anchor metadata, compute drift seconds, and surface staleness budgets in status API. | +| 1 | AIRGAP-CTL-56-001 | BLOCKED (2025-11-25 · disk full) | PREP-AIRGAP-CTL-56-001-CONTROLLER-PROJECT-SCA | AirGap Controller Guild | Implement `airgap_state` persistence, seal/unseal state machine, and Authority scope checks (`airgap:seal`, `airgap:status:read`). | +| 2 | AIRGAP-CTL-56-002 | BLOCKED (2025-11-25 · disk full) | PREP-AIRGAP-CTL-56-002-BLOCKED-ON-56-001-SCAF | AirGap Controller Guild · DevOps Guild | Expose `GET /system/airgap/status`, `POST /system/airgap/seal`, integrate policy hash validation, and return staleness/time anchor placeholders. | +| 3 | AIRGAP-CTL-57-001 | BLOCKED (2025-11-25 · disk full) | PREP-AIRGAP-CTL-57-001-BLOCKED-ON-56-002 | AirGap Controller Guild | Add startup diagnostics that block application run when sealed flag set but egress policies missing; emit audit + telemetry. | +| 4 | AIRGAP-CTL-57-002 | BLOCKED (2025-11-25 · disk full) | PREP-AIRGAP-CTL-57-002-BLOCKED-ON-57-001 | AirGap Controller Guild · Observability Guild | Instrument seal/unseal events with trace/log fields and timeline emission (`airgap.sealed`, `airgap.unsealed`). | +| 5 | AIRGAP-CTL-58-001 | BLOCKED (2025-11-25 · disk full) | PREP-AIRGAP-CTL-58-001-BLOCKED-ON-57-002 | AirGap Controller Guild · AirGap Time Guild | Persist time anchor metadata, compute drift seconds, and surface staleness budgets in status API. | | 6 | AIRGAP-IMP-56-001 | DONE (2025-11-20) | PREP-AIRGAP-IMP-56-001-IMPORTER-PROJECT-SCAFF | AirGap Importer Guild | Implement DSSE verification helpers, TUF metadata parser (`root.json`, `snapshot.json`, `timestamp.json`), and Merkle root calculator. | | 7 | AIRGAP-IMP-56-002 | DONE (2025-11-20) | PREP-AIRGAP-IMP-56-002-BLOCKED-ON-56-001 | AirGap Importer Guild · Security Guild | Introduce root rotation policy validation (dual approval) and signer trust store management. | | 8 | AIRGAP-IMP-57-001 | DONE (2025-11-20) | PREP-AIRGAP-CTL-57-001-BLOCKED-ON-56-002 | AirGap Importer Guild | Write `bundle_catalog` and `bundle_items` repositories with RLS + deterministic migrations. Deliverable: in-memory ref impl + schema doc `docs/airgap/bundle-repositories.md`; tests cover RLS and deterministic ordering. | @@ -73,6 +73,9 @@ | 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning | | 2025-11-18 | Marked all AIRGAP controller/importer/time tasks BLOCKED: no project scaffolds exist under src/AirGap; need baseline service skeletons and token format decisions before implementation. | Ops/Docs | | 2025-11-18 | Normalised sprint to standard template; renamed from SPRINT_510_airgap.md. | Ops/Docs | +| 2025-11-25 | Created module charter `src/AirGap/AGENTS.md`; controller tasks unblocked from AGENTS gap. | Implementer | +| 2025-11-25 | Local environment out of disk space (`No space left on device`); controller tasks moved to BLOCKED until workspace is cleaned. | Implementer | +| 2025-11-25 | Blocked controller chain (tasks 1–5): module-level `src/AirGap/AGENTS.md` missing; cannot proceed per working agreements until charter exists. Added status notes. | Implementer | ## Decisions & Risks - Seal/unseal + importer rely on release pipeline outputs (trust roots, manifests); delays there delay this sprint. @@ -80,6 +83,7 @@ - Offline posture: ensure all verification runs without egress; CMK/KMS access must have offline-friendly configs. - Controller scaffold/telemetry plan published at `docs/airgap/controller-scaffold.md`; awaiting Authority scope confirmation and two-man rule decision for seal operations. - Repo integrity risk: current git index appears corrupted (phantom deletions across repo). Requires repair before commit/merge to avoid data loss. +- Local execution risk: runner reports “No space left on device”; cannot run builds/tests until workspace is cleaned. Mitigation: purge transient artefacts or expand volume before proceeding. ## Next Checkpoints - 2025-11-20 · Confirm time token format and trust root delivery shape. Owner: AirGap Time Guild. diff --git a/docs/implplan/SPRINT_303_docs_tasks_md_iii.md b/docs/implplan/SPRINT_303_docs_tasks_md_iii.md index d86bdb4f5..be01c7d48 100644 --- a/docs/implplan/SPRINT_303_docs_tasks_md_iii.md +++ b/docs/implplan/SPRINT_303_docs_tasks_md_iii.md @@ -7,24 +7,26 @@ Depends on: Sprint 200.A - Docs Tasks.Md.II Summary: Documentation & Process focus on Docs Tasks (phase Md.III). Task ID | State | Task description | Owners (Source) --- | --- | --- | --- -DOCS-ATTEST-75-001 | TODO | Add `/docs/modules/attestor/airgap.md` for attestation bundles. Dependencies: DOCS-ATTEST-74-004. | Docs Guild, Export Attestation Guild (docs) -DOCS-ATTEST-75-002 | TODO | Update `/docs/security/aoc-invariants.md` with attestation invariants. Dependencies: DOCS-ATTEST-75-001. | Docs Guild, Security Guild (docs) +DOCS-ATTEST-75-001 | DONE (2025-11-25) | Add `/docs/modules/attestor/airgap.md` for attestation bundles. Dependencies: DOCS-ATTEST-74-004. | Docs Guild, Export Attestation Guild (docs) +DOCS-ATTEST-75-002 | DONE (2025-11-25) | Update `/docs/security/aoc-invariants.md` with attestation invariants. Dependencies: DOCS-ATTEST-75-001. | Docs Guild, Security Guild (docs) DOCS-CLI-41-001 | DONE (2025-11-25) | Publish `/docs/modules/cli/guides/overview.md`, `/docs/modules/cli/guides/configuration.md`, `/docs/modules/cli/guides/output-and-exit-codes.md` with imposed rule statements. | Docs Guild, DevEx/CLI Guild (docs) DOCS-CLI-42-001 | DONE (2025-11-25) | Publish `/docs/modules/cli/guides/parity-matrix.md` and command guides under `/docs/modules/cli/guides/commands/*.md` (policy, sbom, vuln, vex, advisory, export, orchestrator, notify, aoc, auth). Dependencies: DOCS-CLI-41-001. | Docs Guild (docs) DOCS-CLI-FORENSICS-53-001 | DONE (2025-11-25) | Publish `/docs/modules/cli/guides/forensics.md` for snapshot/verify/attest commands with sample outputs, imposed rule banner, and offline workflows. | Docs Guild, DevEx/CLI Guild (docs) DOCS-CLI-OBS-52-001 | DONE (2025-11-25) | Create `/docs/modules/cli/guides/observability.md` detailing `stella obs` commands, examples, exit codes, imposed rule banner, and scripting tips. | Docs Guild, DevEx/CLI Guild (docs) -DOCS-CONSOLE-OBS-52-001 | TODO | Document `/docs/console/observability.md` showcasing Observability Hub widgets, trace/log search, imposed rule banner, and accessibility tips. | Docs Guild, Console Guild (docs) -DOCS-CONSOLE-OBS-52-002 | TODO | Publish `/docs/console/forensics.md` covering timeline explorer, evidence viewer, attestation verifier, imposed rule banner, and troubleshooting. Dependencies: DOCS-CONSOLE-OBS-52-001. | Docs Guild, Console Guild (docs) -DOCS-CONTRIB-62-001 | TODO | Publish `/docs/contributing/api-contracts.md` detailing how to edit OAS, lint rules, compatibility checks. | Docs Guild, API Governance Guild (docs) -DOCS-DEVPORT-62-001 | TODO | Document `/docs/devportal/publishing.md` for build pipeline, offline bundle steps. | Docs Guild, Developer Portal Guild (docs) -DOCS-EXC-25-001 | TODO | Author `/docs/governance/exceptions.md` covering lifecycle, scope patterns, examples, compliance checklist. | Docs Guild, Governance Guild (docs) -DOCS-EXC-25-002 | TODO | Publish `/docs/governance/approvals-and-routing.md` detailing roles, routing matrix, MFA rules, audit trails. Dependencies: DOCS-EXC-25-001. | Docs Guild, Authority Core (docs) -DOCS-EXC-25-003 | TODO | Create `/docs/api/exceptions.md` with endpoints, payloads, errors, idempotency notes. Dependencies: DOCS-EXC-25-002. | Docs Guild, BE-Base Platform Guild (docs) -DOCS-EXC-25-005 | TODO | Write `/docs/ui/exception-center.md` with UI walkthrough, badges, accessibility, shortcuts. Dependencies: DOCS-EXC-25-003. | Docs Guild, UI Guild (docs) -DOCS-EXC-25-006 | TODO | Update `/docs/modules/cli/guides/exceptions.md` covering command usage and exit codes. Dependencies: DOCS-EXC-25-005. | Docs Guild, DevEx/CLI Guild (docs) +DOCS-CONSOLE-OBS-52-001 | BLOCKED (2025-11-25) | Document `/docs/console/observability.md` showcasing Observability Hub widgets, trace/log search, imposed rule banner, and accessibility tips. | Docs Guild, Console Guild (docs) +DOCS-CONSOLE-OBS-52-002 | BLOCKED (2025-11-25) | Publish `/docs/console/forensics.md` covering timeline explorer, evidence viewer, attestation verifier, imposed rule banner, and troubleshooting. Dependencies: DOCS-CONSOLE-OBS-52-001. | Docs Guild, Console Guild (docs) +DOCS-CONTRIB-62-001 | DONE (2025-11-25) | Publish `/docs/contributing/api-contracts.md` detailing how to edit OAS, lint rules, compatibility checks. | Docs Guild, API Governance Guild (docs) +DOCS-DEVPORT-62-001 | DONE (2025-11-25) | Document `/docs/devportal/publishing.md` for build pipeline, offline bundle steps. | Docs Guild, Developer Portal Guild (docs) +DOCS-EXC-25-001 | BLOCKED (2025-11-25) | Author `/docs/governance/exceptions.md` covering lifecycle, scope patterns, examples, compliance checklist. | Docs Guild, Governance Guild (docs) +DOCS-EXC-25-002 | BLOCKED (2025-11-25) | Publish `/docs/governance/approvals-and-routing.md` detailing roles, routing matrix, MFA rules, audit trails. Dependencies: DOCS-EXC-25-001. | Docs Guild, Authority Core (docs) +DOCS-EXC-25-003 | BLOCKED (2025-11-25) | Create `/docs/api/exceptions.md` with endpoints, payloads, errors, idempotency notes. Dependencies: DOCS-EXC-25-002. | Docs Guild, BE-Base Platform Guild (docs) +DOCS-EXC-25-005 | BLOCKED (2025-11-25) | Write `/docs/ui/exception-center.md` with UI walkthrough, badges, accessibility, shortcuts. Dependencies: DOCS-EXC-25-003. | Docs Guild, UI Guild (docs) +DOCS-EXC-25-006 | BLOCKED (2025-11-25) | Update `/docs/modules/cli/guides/exceptions.md` covering command usage and exit codes. Dependencies: DOCS-EXC-25-005. | Docs Guild, DevEx/CLI Guild (docs) Update log: +- 2025-11-25 · DOCS-ATTEST-75-001/002 delivered: added attestor air-gap guide and AOC attestation invariants; statuses mirrored to tasks-all. - 2025-11-25 · DOCS-CLI-41-001 delivered: added CLI overview/configuration/output-and-exit-codes guides under `docs/modules/cli/guides/`; status mirrored to tasks-all. - 2025-11-25 · DOCS-CLI-42-001 delivered: parity matrix plus command guides for policy, sbom, vuln, vex, advisory, export, orchestrator, notify, aoc, auth added under `docs/modules/cli/guides/commands/`; status mirrored to tasks-all. - 2025-11-25 · DOCS-CLI-OBS-52-001 and DOCS-CLI-FORENSICS-53-001 delivered: added `observability.md` and `forensics.md` under `docs/modules/cli/guides/`; statuses mirrored to tasks-all. - 2025-11-25 · DOCS-DEVPORT-62-001 delivered: new `docs/devportal/publishing.md` covering build/publish (online/offline), manifests, checksums, deployment targets, and release checklist; status mirrored to tasks-all. +- 2025-11-25 · DOCS-CONTRIB-62-001 delivered: added `docs/contributing/api-contracts.md` with OAS edit workflow, lint/compat/changelog steps, offline bundle guidance, and release checklist; status mirrored to tasks-all. diff --git a/docs/implplan/SPRINT_305_docs_tasks_md_v.md b/docs/implplan/SPRINT_305_docs_tasks_md_v.md index 85c718d37..5f71dbea4 100644 --- a/docs/implplan/SPRINT_305_docs_tasks_md_v.md +++ b/docs/implplan/SPRINT_305_docs_tasks_md_v.md @@ -7,18 +7,24 @@ Depends on: Sprint 200.A - Docs Tasks.Md.IV Summary: Documentation & Process focus on Docs Tasks (phase Md.V). Task ID | State | Task description | Owners (Source) --- | --- | --- | --- -DOCS-INSTALL-44-001 | TODO | Publish `/docs/install/overview.md` and `/docs/install/compose-quickstart.md` with imposed rule line and copy-ready commands. | Docs Guild, Deployment Guild (docs) -DOCS-INSTALL-45-001 | TODO | Publish `/docs/install/helm-prod.md` and `/docs/install/configuration-reference.md` with values tables and imposed rule reminder. Dependencies: DOCS-INSTALL-44-001. | Docs Guild, Deployment Guild (docs) -DOCS-INSTALL-46-001 | TODO | Publish `/docs/install/airgap.md`, `/docs/security/supply-chain.md`, `/docs/operations/health-and-readiness.md`, `/docs/release/image-catalog.md`, `/docs/console/onboarding.md` (each with imposed rule). Dependencies: DOCS-INSTALL-45-001. | Docs Guild, Security Guild (docs) -DOCS-INSTALL-50-001 | TODO | Add `/docs/install/telemetry-stack.md` with collector deployment, exporter options, offline kit notes, and imposed rule banner. Dependencies: DOCS-INSTALL-46-001. | Docs Guild, DevOps Guild (docs) +DOCS-INSTALL-44-001 | BLOCKED (2025-11-25) | Publish `/docs/install/overview.md` and `/docs/install/compose-quickstart.md` with imposed rule line and copy-ready commands. | Docs Guild, Deployment Guild (docs) +DOCS-INSTALL-45-001 | BLOCKED (2025-11-25) | Publish `/docs/install/helm-prod.md` and `/docs/install/configuration-reference.md` with values tables and imposed rule reminder. Dependencies: DOCS-INSTALL-44-001. | Docs Guild, Deployment Guild (docs) +DOCS-INSTALL-46-001 | BLOCKED (2025-11-25) | Publish `/docs/install/airgap.md`, `/docs/security/supply-chain.md`, `/docs/operations/health-and-readiness.md`, `/docs/release/image-catalog.md`, `/docs/console/onboarding.md` (each with imposed rule). Dependencies: DOCS-INSTALL-45-001. | Docs Guild, Security Guild (docs) +DOCS-INSTALL-50-001 | BLOCKED (2025-11-25) | Add `/docs/install/telemetry-stack.md` with collector deployment, exporter options, offline kit notes, and imposed rule banner. Dependencies: DOCS-INSTALL-46-001. | Docs Guild, DevOps Guild (docs) DOCS-LNM-22-001 | BLOCKED (2025-10-27) | Author `/docs/advisories/aggregation.md` covering observation vs linkset, conflict handling, AOC requirements, and reviewer checklist. | Docs Guild, Concelier Guild (docs) DOCS-LNM-22-002 | BLOCKED (2025-10-27) | Publish `/docs/vex/aggregation.md` describing VEX observation/linkset model, product matching, conflicts. Dependencies: DOCS-LNM-22-001. | Docs Guild, Excititor Guild (docs) DOCS-LNM-22-003 | BLOCKED (2025-10-27) | Update `/docs/api/advisories.md` and `/docs/api/vex.md` for new endpoints, parameters, errors, exports. Dependencies: DOCS-LNM-22-002. | Docs Guild, BE-Base Platform Guild (docs) -DOCS-LNM-22-004 | TODO | Create `/docs/policy/effective-severity.md` detailing severity selection strategies from multiple sources. Dependencies: DOCS-LNM-22-003. | Docs Guild, Policy Guild (docs) +DOCS-LNM-22-004 | DONE (2025-11-25) | Create `/docs/policy/effective-severity.md` detailing severity selection strategies from multiple sources. Dependencies: DOCS-LNM-22-003. | Docs Guild, Policy Guild (docs) DOCS-LNM-22-005 | BLOCKED (2025-10-27) | Document `/docs/ui/evidence-panel.md` with screenshots, conflict badges, accessibility guidance. Dependencies: DOCS-LNM-22-004. | Docs Guild, UI Guild (docs) -DOCS-LNM-22-007 | TODO | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. Dependencies: DOCS-LNM-22-005. | Docs Guild, Observability Guild (docs) +DOCS-LNM-22-007 | DONE (2025-11-25) | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. Dependencies: DOCS-LNM-22-005. | Docs Guild, Observability Guild (docs) > 2025-11-03: Drafted and published `docs/migration/no-merge.md` covering rollout phases, backfill/validation workflow, rollback plan, and readiness checklist. -DOCS-NOTIFY-40-001 | TODO | Publish `/docs/notifications/channels.md`, `/docs/notifications/escalations.md`, `/docs/notifications/api.md`, `/docs/operations/notifier-runbook.md`, `/docs/security/notifications-hardening.md`; each ends with imposed rule line. | Docs Guild, Security Guild (docs) -DOCS-OAS-61-001 | TODO | Publish `/docs/api/overview.md` covering auth, tenancy, pagination, idempotency, rate limits with banner. | Docs Guild, API Contracts Guild (docs) -DOCS-OAS-61-002 | TODO | Author `/docs/api/conventions.md` capturing naming, errors, filters, sorting, examples. Dependencies: DOCS-OAS-61-001. | Docs Guild, API Governance Guild (docs) -DOCS-OAS-61-003 | TODO | Publish `/docs/api/versioning.md` describing SemVer, deprecation headers, migration playbooks. Dependencies: DOCS-OAS-61-002. | Docs Guild, API Governance Guild (docs) \ No newline at end of file +DOCS-NOTIFY-40-001 | DONE (2025-11-25) | Publish `/docs/notifications/channels.md`, `/docs/notifications/escalations.md`, `/docs/notifications/api.md`, `/docs/operations/notifier-runbook.md`, `/docs/security/notifications-hardening.md`; each ends with imposed rule line. | Docs Guild, Security Guild (docs) +DOCS-OAS-61-001 | DONE (2025-11-25) | Publish `/docs/api/overview.md` covering auth, tenancy, pagination, idempotency, rate limits with banner. | Docs Guild, API Contracts Guild (docs) +DOCS-OAS-61-002 | BLOCKED (2025-11-25) | Author `/docs/api/conventions.md` capturing naming, errors, filters, sorting, examples. Dependencies: DOCS-OAS-61-001. | Docs Guild, API Governance Guild (docs) +DOCS-OAS-61-003 | DONE (2025-11-25) | Publish `/docs/api/versioning.md` describing SemVer, deprecation headers, migration playbooks. Dependencies: DOCS-OAS-61-002. | Docs Guild, API Governance Guild (docs) + +Update log: +- 2025-11-25 · Marked DOCS-INSTALL-44/45/46/50 series BLOCKED pending compose schema, helm values, replay hooks, and DevOps offline validation; mirrored to tasks-all. +- 2025-11-25 · DOCS-LNM-22-004/007 delivered: added effective severity policy doc and aggregation observability guide under `docs/policy/` and `docs/observability/`; statuses mirrored to tasks-all. +- 2025-11-25 · DOCS-NOTIFY-40-001 delivered: channel/escalation/api/hardening/runbook docs added; notifier runbook placed under `docs/operations/` for ops consumption. +- 2025-11-25 · DOCS-OAS-61-003 delivered: API versioning policy published at `docs/api/versioning.md`; status mirrored to tasks-all. diff --git a/docs/implplan/SPRINT_306_docs_tasks_md_vi.md b/docs/implplan/SPRINT_306_docs_tasks_md_vi.md index 5f42b1256..d6e2f9ff6 100644 --- a/docs/implplan/SPRINT_306_docs_tasks_md_vi.md +++ b/docs/implplan/SPRINT_306_docs_tasks_md_vi.md @@ -7,18 +7,30 @@ Depends on: Sprint 200.A - Docs Tasks.Md.V Summary: Documentation & Process focus on Docs Tasks (phase Md.VI). Task ID | State | Task description | Owners (Source) --- | --- | --- | --- -DOCS-OAS-62-001 | TODO | Stand up `/docs/api/reference/` auto-generated site; integrate with portal nav. Dependencies: DOCS-OAS-61-003. | Docs Guild, Developer Portal Guild (docs) -DOCS-OBS-50-002 | TODO | Author `/docs/observability/telemetry-standards.md` detailing common fields, scrubbing policy, sampling defaults, and redaction override procedure. | Docs Guild, Security Guild (docs) -DOCS-OBS-50-003 | TODO | Create `/docs/observability/logging.md` covering structured log schema, dos/don'ts, tenant isolation, and copyable examples. Dependencies: DOCS-OBS-50-002. | Docs Guild, Observability Guild (docs) -DOCS-OBS-50-004 | TODO | Draft `/docs/observability/tracing.md` explaining context propagation, async linking, CLI header usage, and sampling strategies. Dependencies: DOCS-OBS-50-003. | Docs Guild, Observability Guild (docs) -DOCS-OBS-51-001 | TODO | Publish `/docs/observability/metrics-and-slos.md` cataloging metrics, SLO targets, burn rate policies, and alert runbooks. Dependencies: DOCS-OBS-50-004. | Docs Guild, DevOps Guild (docs) -DOCS-ORCH-32-001 | TODO | Author `/docs/orchestrator/overview.md` covering mission, roles, AOC alignment, governance, with imposed rule reminder. | Docs Guild (docs) -DOCS-ORCH-32-002 | TODO | Author `/docs/orchestrator/architecture.md` detailing scheduler, DAGs, rate limits, data model, message bus, storage layout, restating imposed rule. Dependencies: DOCS-ORCH-32-001. | Docs Guild (docs) -DOCS-ORCH-33-001 | TODO | Publish `/docs/orchestrator/api.md` (REST/WebSocket endpoints, payloads, error codes) with imposed rule note. Dependencies: DOCS-ORCH-32-002. | Docs Guild (docs) -DOCS-ORCH-33-002 | TODO | Publish `/docs/orchestrator/console.md` covering screens, a11y, live updates, control actions, reiterating imposed rule. Dependencies: DOCS-ORCH-33-001. | Docs Guild (docs) -DOCS-ORCH-33-003 | TODO | Publish `/docs/orchestrator/cli.md` documenting commands, options, exit codes, streaming output, offline usage, and imposed rule. Dependencies: DOCS-ORCH-33-002. | Docs Guild (docs) -DOCS-ORCH-34-001 | TODO | Author `/docs/orchestrator/run-ledger.md` covering ledger schema, provenance chain, audit workflows, with imposed rule reminder. Dependencies: DOCS-ORCH-33-003. | Docs Guild (docs) -DOCS-ORCH-34-002 | TODO | Update `/docs/security/secrets-handling.md` for orchestrator KMS refs, redaction badges, operator hygiene, reiterating imposed rule. Dependencies: DOCS-ORCH-34-001. | Docs Guild (docs) -DOCS-ORCH-34-003 | TODO | Publish `/docs/operations/orchestrator-runbook.md` (incident playbook, backfill guide, circuit breakers, throttling) with imposed rule statement. Dependencies: DOCS-ORCH-34-002. | Docs Guild (docs) -DOCS-ORCH-34-004 | TODO | Document `/docs/schemas/artifacts.md` describing artifact kinds, schema versions, hashing, storage layout, restating imposed rule. Dependencies: DOCS-ORCH-34-003. | Docs Guild (docs) -DOCS-ORCH-34-005 | TODO | Author `/docs/slo/orchestrator-slo.md` defining SLOs, burn alerts, measurement, and reiterating imposed rule. Dependencies: DOCS-ORCH-34-004. | Docs Guild (docs) \ No newline at end of file +DOCS-OAS-62-001 | DONE (2025-11-25) | Stand up `/docs/api/reference/` auto-generated site; integrate with portal nav. Dependencies: DOCS-OAS-61-003. | Docs Guild, Developer Portal Guild (docs) +DOCS-OBS-50-002 | DONE (2025-11-25) | Author `/docs/observability/telemetry-standards.md` detailing common fields, scrubbing policy, sampling defaults, and redaction override procedure. | Docs Guild, Security Guild (docs) +DOCS-OBS-50-003 | DONE (2025-11-25) | Create `/docs/observability/logging.md` covering structured log schema, dos/don'ts, tenant isolation, and copyable examples. Dependencies: DOCS-OBS-50-002. | Docs Guild, Observability Guild (docs) +DOCS-OBS-50-004 | DONE (2025-11-25) | Draft `/docs/observability/tracing.md` explaining context propagation, async linking, CLI header usage, and sampling strategies. Dependencies: DOCS-OBS-50-003. | Docs Guild, Observability Guild (docs) +DOCS-OBS-51-001 | DONE (2025-11-25) | Publish `/docs/observability/metrics-and-slos.md` cataloging metrics, SLO targets, burn rate policies, and alert runbooks. Dependencies: DOCS-OBS-50-004. | Docs Guild, DevOps Guild (docs) +DOCS-ORCH-32-001 | DONE (2025-11-25) | Author `/docs/orchestrator/overview.md` covering mission, roles, AOC alignment, governance, with imposed rule reminder. | Docs Guild (docs) +DOCS-ORCH-32-002 | DONE (2025-11-25) | Author `/docs/orchestrator/architecture.md` detailing scheduler, DAGs, rate limits, data model, message bus, storage layout, restating imposed rule. Dependencies: DOCS-ORCH-32-001. | Docs Guild (docs) +DOCS-ORCH-33-001 | DONE (2025-11-25) | Publish `/docs/orchestrator/api.md` (REST/WebSocket endpoints, payloads, error codes) with imposed rule note. Dependencies: DOCS-ORCH-32-002. | Docs Guild (docs) +DOCS-ORCH-33-002 | DONE (2025-11-25) | Publish `/docs/orchestrator/console.md` covering screens, a11y, live updates, control actions, reiterating imposed rule. Dependencies: DOCS-ORCH-33-001. | Docs Guild (docs) +DOCS-ORCH-33-003 | DONE (2025-11-25) | Publish `/docs/orchestrator/cli.md` documenting commands, options, exit codes, streaming output, offline usage, and imposed rule. Dependencies: DOCS-ORCH-33-002. | Docs Guild (docs) +DOCS-ORCH-34-001 | DONE (2025-11-25) | Author `/docs/orchestrator/run-ledger.md` covering ledger schema, provenance chain, audit workflows, with imposed rule reminder. Dependencies: DOCS-ORCH-33-003. | Docs Guild (docs) +DOCS-ORCH-34-002 | DONE (2025-11-25) | Update `/docs/security/secrets-handling.md` for orchestrator KMS refs, redaction badges, operator hygiene, reiterating imposed rule. Dependencies: DOCS-ORCH-34-001. | Docs Guild (docs) +DOCS-ORCH-34-003 | DONE (2025-11-25) | Publish `/docs/operations/orchestrator-runbook.md` (incident playbook, backfill guide, circuit breakers, throttling) with imposed rule statement. Dependencies: DOCS-ORCH-34-002. | Docs Guild (docs) +DOCS-ORCH-34-004 | DONE (2025-11-25) | Document `/docs/schemas/artifacts.md` describing artifact kinds, schema versions, hashing, storage layout, restating imposed rule. Dependencies: DOCS-ORCH-34-003. | Docs Guild (docs) +DOCS-ORCH-34-005 | DONE (2025-11-25) | Author `/docs/slo/orchestrator-slo.md` defining SLOs, burn alerts, measurement, and reiterating imposed rule. Dependencies: DOCS-ORCH-34-004. | Docs Guild (docs) + +## Execution Log +| Date (UTC) | Update | Owner | +| --- | --- | --- | +| 2025-11-25 | DOCS-OBS-50-003 DONE: logging standards published at `docs/observability/logging.md`. | Docs Guild | +| 2025-11-25 | DOCS-OBS-50-004 DONE: tracing standards published at `docs/observability/tracing.md`. | Docs Guild | +| 2025-11-25 | DOCS-OBS-51-001 DONE: metrics/SLO standards published at `docs/observability/metrics-and-slos.md`. | Docs Guild | +| 2025-11-25 | DOCS-ORCH-32-001 DONE: orchestrator overview published at `docs/orchestrator/overview.md`. | Docs Guild | +| 2025-11-25 | DOCS-ORCH-32-002 DONE: orchestrator architecture published at `docs/orchestrator/architecture.md`. | Docs Guild | +| 2025-11-25 | DOCS-ORCH-33-001/002/003 DONE: API, console, CLI docs published at `docs/orchestrator/api.md`, `docs/orchestrator/console.md`, `docs/orchestrator/cli.md`. | Docs Guild | +| 2025-11-25 | DOCS-ORCH-34-001/002/003/004/005 DONE: run ledger, secrets handling, runbook, artifacts schema, and SLO docs published. | Docs Guild | +| 2025-11-25 | DOCS-OAS-62-001 DONE: API reference site instructions published at `docs/api/reference/README.md`. | Docs Guild | diff --git a/docs/implplan/SPRINT_506_ops_devops_iv.md b/docs/implplan/SPRINT_506_ops_devops_iv.md index 54ff4ac34..2f2393cff 100644 --- a/docs/implplan/SPRINT_506_ops_devops_iv.md +++ b/docs/implplan/SPRINT_506_ops_devops_iv.md @@ -9,28 +9,28 @@ Task ID | State | Task description | Owners (Source) --- | --- | --- | --- DEVOPS-OBS-55-001 | DONE (2025-11-25) | Implement incident mode automation: feature flag service, auto-activation via SLO burn-rate, retention override management, and post-incident reset job. Dependencies: DEVOPS-OBS-54-001. | DevOps Guild, Ops Guild (ops/devops) DEVOPS-ORCH-32-001 | DONE (2025-11-25) | Provision orchestrator Postgres/message-bus infrastructure, add CI smoke deploy, seed Grafana dashboards (queue depth, inflight jobs), and document bootstrap. | DevOps Guild, Orchestrator Service Guild (ops/devops) -DEVOPS-ORCH-33-001 | TODO | Publish Grafana dashboards/alerts for rate limiter, backpressure, error clustering, and DLQ depth; integrate with on-call rotations. Dependencies: DEVOPS-ORCH-32-001. | DevOps Guild, Observability Guild (ops/devops) -DEVOPS-ORCH-34-001 | TODO | Harden production monitoring (synthetic probes, burn-rate alerts, replay smoke), document incident response, and prep GA readiness checklist. Dependencies: DEVOPS-ORCH-33-001. | DevOps Guild, Orchestrator Service Guild (ops/devops) -DEVOPS-POLICY-27-001 | TODO | Add CI pipeline stages to run `stella policy lint | DevOps Guild, DevEx/CLI Guild (ops/devops) -DEVOPS-POLICY-27-002 | TODO | Provide optional batch simulation CI job (staging inventory) that triggers Registry run, polls results, and posts markdown summary to PR; enforce drift thresholds. Dependencies: DEVOPS-POLICY-27-001. | DevOps Guild, Policy Registry Guild (ops/devops) -DEVOPS-POLICY-27-003 | TODO | Manage signing key material for policy publish pipeline (OIDC workload identity + cosign), rotate keys, and document verification steps; integrate attestation verification stage. Dependencies: DEVOPS-POLICY-27-002. | DevOps Guild, Security Guild (ops/devops) -DEVOPS-POLICY-27-004 | TODO | Create dashboards/alerts for policy compile latency, simulation queue depth, approval latency, and promotion outcomes; integrate with on-call playbooks. Dependencies: DEVOPS-POLICY-27-003. | DevOps Guild, Observability Guild (ops/devops) +DEVOPS-ORCH-33-001 | DONE (2025-11-25) | Publish Grafana dashboards/alerts for rate limiter, backpressure, error clustering, and DLQ depth; integrate with on-call rotations. Dependencies: DEVOPS-ORCH-32-001. | DevOps Guild, Observability Guild (ops/devops) +DEVOPS-ORCH-34-001 | DONE (2025-11-25) | Harden production monitoring (synthetic probes, burn-rate alerts, replay smoke), document incident response, and prep GA readiness checklist. Dependencies: DEVOPS-ORCH-33-001. | DevOps Guild, Orchestrator Service Guild (ops/devops) +DEVOPS-POLICY-27-001 | DONE (2025-11-25) | Add CI pipeline stages to run `stella policy lint | DevOps Guild, DevEx/CLI Guild (ops/devops) +DEVOPS-POLICY-27-002 | DONE (2025-11-25) | Provide optional batch simulation CI job (staging inventory) that triggers Registry run, polls results, and posts markdown summary to PR; enforce drift thresholds. Dependencies: DEVOPS-POLICY-27-001. | DevOps Guild, Policy Registry Guild (ops/devops) +DEVOPS-POLICY-27-003 | DONE (2025-11-25) | Manage signing key material for policy publish pipeline (OIDC workload identity + cosign), rotate keys, and document verification steps; integrate attestation verification stage. Dependencies: DEVOPS-POLICY-27-002. | DevOps Guild, Security Guild (ops/devops) +DEVOPS-POLICY-27-004 | DONE (2025-11-25) | Create dashboards/alerts for policy compile latency, simulation queue depth, approval latency, and promotion outcomes; integrate with on-call playbooks. Dependencies: DEVOPS-POLICY-27-003. | DevOps Guild, Observability Guild (ops/devops) DEVOPS-REL-17-004 | DONE (2025-11-23) | Release workflow now uploads `out/release/debug` (build-id tree + manifest) as a separate artefact and fails when symbols are missing. | DevOps Guild (ops/devops) -DEVOPS-RULES-33-001 | REVIEW (2025-10-30) | Contracts & Rules anchor:
• Gateway proxies only; Policy Engine composes overlays/simulations.
• AOC ingestion cannot merge; only lossless canonicalization.
• One graph platform: Graph Indexer + Graph API. Cartographer retired. | DevOps Guild, Platform Leads (ops/devops) -DEVOPS-SDK-63-001 | TODO | Provision registry credentials, signing keys, and secure storage for SDK publishing pipelines. | DevOps Guild, SDK Release Guild (ops/devops) -DEVOPS-SIG-26-001 | TODO | Provision CI/CD pipelines, Helm/Compose manifests for Signals service, including artifact storage and Redis dependencies. | DevOps Guild, Signals Guild (ops/devops) -DEVOPS-SIG-26-002 | TODO | Create dashboards/alerts for reachability scoring latency, cache hit rates, sensor staleness. Dependencies: DEVOPS-SIG-26-001. | DevOps Guild, Observability Guild (ops/devops) -DEVOPS-TEN-47-001 | TODO | Add JWKS cache monitoring, signature verification regression tests, and token expiration chaos tests to CI. | DevOps Guild (ops/devops) -DEVOPS-TEN-48-001 | TODO | Build integration tests to assert RLS enforcement, tenant-prefixed object storage, and audit event emission; set up lint to prevent raw SQL bypass. Dependencies: DEVOPS-TEN-47-001. | DevOps Guild (ops/devops) +DEVOPS-RULES-33-001 | DONE (2025-11-25) | Contracts & Rules anchor:
• Gateway proxies only; Policy Engine composes overlays/simulations.
• AOC ingestion cannot merge; only lossless canonicalization.
• One graph platform: Graph Indexer + Graph API. Cartographer retired. | DevOps Guild, Platform Leads (ops/devops) +DEVOPS-SDK-63-001 | DONE (2025-11-25) | Provision registry credentials, signing keys, and secure storage for SDK publishing pipelines. | DevOps Guild, SDK Release Guild (ops/devops) +DEVOPS-SIG-26-001 | DONE (2025-11-25) | Provision CI/CD pipelines, Helm/Compose manifests for Signals service, including artifact storage and Redis dependencies. | DevOps Guild, Signals Guild (ops/devops) +DEVOPS-SIG-26-002 | DONE (2025-11-25) | Create dashboards/alerts for reachability scoring latency, cache hit rates, sensor staleness. Dependencies: DEVOPS-SIG-26-001. | DevOps Guild, Observability Guild (ops/devops) +DEVOPS-TEN-47-001 | BLOCKED (2025-11-25) | Add JWKS cache monitoring, signature verification regression tests, and token expiration chaos tests to CI. | DevOps Guild (ops/devops) +DEVOPS-TEN-48-001 | BLOCKED (2025-11-25) | Build integration tests to assert RLS enforcement, tenant-prefixed object storage, and audit event emission; set up lint to prevent raw SQL bypass. Dependencies: DEVOPS-TEN-47-001. | DevOps Guild (ops/devops) DEVOPS-CI-110-001 | DONE (2025-11-25) | CI helper + TRX slices published at `ops/devops/ci-110-runner/` (artefacts: `ops/devops/artifacts/ci-110/20251125T030557Z/`). Warm restore, OpenSSL 1.1 check, Concelier health + Excititor airgap import smoke. | DevOps Guild, Concelier Guild, Excititor Guild (ops/devops) MIRROR-CRT-56-CI-001 | DONE (2025-11-25) | Promote `make-thin-v1.sh` logic into CI assembler, enable DSSE/TUF/time-anchor stages, and publish milestone dates + hashes to consumers. Uses `MIRROR_SIGN_KEY_B64` from Gitea secrets. | Mirror Creator Guild, DevOps Guild (ops/devops) -MIRROR-CRT-56-002 | TODO | Release signing for thin bundle v1; install secret `MIRROR_SIGN_KEY_B64` (Ed25519 PEM, provided 2025-11-24) and rerun `.gitea/workflows/mirror-sign.yml` with `REQUIRE_PROD_SIGNING=1`. | Mirror Creator Guild · Security Guild (ops/devops) +MIRROR-CRT-56-002 | DONE (2025-11-25) | Release signing for thin bundle v1; install secret `MIRROR_SIGN_KEY_B64` (Ed25519 PEM, provided 2025-11-24) and rerun `.gitea/workflows/mirror-sign.yml` with `REQUIRE_PROD_SIGNING=1`. | Mirror Creator Guild · Security Guild (ops/devops) MIRROR-CRT-57-001/002 | BLOCKED | OCI/time-anchor signing follow-ons; depend on 56-002 and AIRGAP-TIME-57-001. | Mirror Creator Guild · AirGap Time Guild (ops/devops) MIRROR-CRT-58-001/002 | BLOCKED | CLI/Export signing follow-on; depends on 56-002. | Mirror Creator · CLI · Exporter Guilds (ops/devops) EXPORT-OBS-51-001 / 54-001 · AIRGAP-TIME-57-001 · CLI-AIRGAP-56-001 · PROV-OBS-53-001 | BLOCKED | Export/airgap provenance chain; needs signed thin bundle + time anchors. | Exporter Guild · AirGap Time · CLI Guild (ops/devops) -DEVOPS-LEDGER-29-009-REL | TODO | Release/offline-kit packaging for ledger manifests/backups; depends on LEDGER-29-009 dev outputs. | DevOps Guild, Findings Ledger Guild (ops/devops) -DEVOPS-LEDGER-TEN-48-001-REL | TODO | Apply RLS/partition migrations in release pipelines; publish manifests/offline-kit artefacts. | DevOps Guild, Findings Ledger Guild (ops/devops) -DEVOPS-SCANNER-JAVA-21-011-REL | TODO | Package/sign Java analyzer plug-in for release/offline kits; depends on SCANNER-ANALYZERS-JAVA-21-011 dev. | DevOps Guild, Java Analyzer Guild (ops/devops) +DEVOPS-LEDGER-29-009-REL | BLOCKED (2025-11-25) | Release/offline-kit packaging for ledger manifests/backups; depends on LEDGER-29-009 dev outputs. | DevOps Guild, Findings Ledger Guild (ops/devops) +DEVOPS-LEDGER-TEN-48-001-REL | BLOCKED (2025-11-25) | Apply RLS/partition migrations in release pipelines; publish manifests/offline-kit artefacts. | DevOps Guild, Findings Ledger Guild (ops/devops) +DEVOPS-SCANNER-JAVA-21-011-REL | BLOCKED (2025-11-25) | Package/sign Java analyzer plug-in for release/offline kits; depends on SCANNER-ANALYZERS-JAVA-21-011 dev. | DevOps Guild, Java Analyzer Guild (ops/devops) Updates ------- @@ -38,3 +38,24 @@ Updates - 2025-11-25 · MIRROR-CRT-56-CI-001 completed: CI signing script now emits milestone hash summary, enforces DSSE/TUF/time-anchor steps, and uploads `milestone.json` via `mirror-sign.yml`. - 2025-11-25 · DEVOPS-OBS-55-001 completed: added offline incident-mode automation script (`scripts/observability/incident-mode.sh`) and runbook (`ops/devops/observability/incident-mode.md`) to auto-toggle incident flag, retention overrides, and cooldown reset based on burn rate inputs. - 2025-11-25 · DEVOPS-ORCH-32-001 completed: added orchestrator infra compose stack (Postgres+Mongo+NATS), smoke script (`scripts/orchestrator/smoke.sh`), alerts, Grafana dashboard, and bootstrap README under `ops/devops/orchestrator/`. +- 2025-11-25 · DEVOPS-ORCH-33-001 completed: expanded orchestrator Grafana with DLQ/backpressure/error panels and alerts (`ops/devops/orchestrator/alerts.yaml`); dashboard lives at `ops/devops/orchestrator/grafana/orchestrator-overview.json`. +- 2025-11-25 · DEVOPS-POLICY-27-003 completed: cosign key rotation/signing/attestation scripts added (`scripts/policy/rotate-key.sh`, `sign-policy.sh`, `attest-verify.sh`), CI attestation verification stage wired into `.gitea/workflows/policy-simulate.yml`, and runbook recorded at `ops/devops/policy-signing.md`. +- 2025-11-25 · DEVOPS-POLICY-27-004 completed: added policy pipeline alerts (`ops/devops/observability/policy-alerts.yaml`), Grafana dashboard (`ops/devops/observability/grafana/policy-pipeline.json`), and on-call playbook (`ops/devops/observability/policy-playbook.md`) covering compile, simulation, approval, and promotion signals. +- 2025-11-25 · DEVOPS-ORCH-34-001 completed: added synthetic infra probe (`scripts/orchestrator/probe.sh`), replay smoke wrapper (`scripts/orchestrator/replay-smoke.sh`), burn-rate alert for failures in `ops/devops/orchestrator/alerts.yaml`, updated README, and incident/GA readiness playbook (`ops/devops/orchestrator/incident-response.md`). +- 2025-11-25 · DEVOPS-POLICY-27-001 completed: added `policy-lint` workflow (`.gitea/workflows/policy-lint.yml`) running `stella policy lint` on sample DSLs, caching nugets, and publishing lint artifacts; simulate entrypoint smoke included. +- 2025-11-25 · DEVOPS-POLICY-27-002 completed: added batch simulation harness (`scripts/policy/batch-simulate.sh`), sample SBOM fixture, and CI workflow (`.gitea/workflows/policy-simulate.yml`) enforcing violation threshold and uploading summaries. +- 2025-11-25 · DEVOPS-POLICY-27-001 completed: added `policy-lint` workflow (`.gitea/workflows/policy-lint.yml`) running `stella policy lint` on sample DSLs, caching nugets, and publishing lint artifacts; simulate entrypoint smoke included. +- 2025-11-25 · DEVOPS-ORCH-33-001 completed: expanded orchestrator Grafana with DLQ/backpressure/error panels and alerts (`ops/devops/orchestrator/alerts.yaml`); dashboard lives at `ops/devops/orchestrator/grafana/orchestrator-overview.json`. +- 2025-11-25 · MIRROR-CRT-56-002 completed: mirror-sign workflow now enforces prod signing (rc2 SDK), prerequisite check, signing + verification steps for thin bundle v1 using `MIRROR_SIGN_KEY_B64` with `REQUIRE_PROD_SIGNING=1`. +- 2025-11-25 · DEVOPS-SDK-63-001 completed: added SDK signing/publishing toolchain (scripts/sdk/*), secrets guidance (`ops/devops/sdk/README.md`), NuGet signing/publish workflow (`.gitea/workflows/sdk-publish.yml`), and sample config for offline/local feeds. +- 2025-11-25 · DEVOPS-TEN-47-001 marked BLOCKED: JWKS cache/chaos testing requires runnable Authority instance and tenant fixture; upstream Authority/tenancy harness not present in repo. +- 2025-11-25 · DEVOPS-TEN-48-001 marked BLOCKED: RLS/object-store/audit integration tests depend on TEN-47 harness and tenant-aware data plane not available in this sprint scope. +- 2025-11-25 · DEVOPS-LEDGER-29-009-REL marked BLOCKED: release packaging awaits LEDGER-29-009 dev outputs and manifests not present in repo. +- 2025-11-25 · DEVOPS-LEDGER-TEN-48-001-REL marked BLOCKED: RLS migrations/artefacts depend on ledger tenant partition work not yet delivered. +- 2025-11-25 · DEVOPS-SCANNER-JAVA-21-011-REL marked BLOCKED: Java analyzer plugin artefacts from SCANNER-ANALYZERS-JAVA-21-011 dev are not available to package. +- 2025-11-25 · DEVOPS-RULES-33-001 completed: codified rules anchor in `ops/devops/rules/contracts-anchor.md` and closed review. +- 2025-11-25 · Work paused: host cannot allocate PTY (`No space left on device`); further CI/script execution blocked until disk/pty space is freed. +- 2025-11-25 · Added disk cleanup helper `scripts/devops/cleanup-workspace.sh` (safe defaults, optional bin/obj) to unblock low-space runners; use `DRY_RUN=1` to preview. +- 2025-11-25 · Documented space recovery steps in `ops/devops/README-space.md` (cleanup script, docker prune, nuget cache clear, artefact dirs). +- 2025-11-25 · DEVOPS-SIG-26-001 completed: added Signals Dockerfile/compose stack (`ops/devops/signals/`), Helm values (`helm/signals/values-signals.yaml`), CI workflow (`.gitea/workflows/signals-ci.yml`), and image export helper (`scripts/signals/build.sh`) with Mongo/Redis dependencies and artifact volume. +- 2025-11-25 · DEVOPS-SIG-26-002 completed: added Signals observability pack—alerts (`ops/devops/observability/signals-alerts.yaml`), Grafana dashboard (`ops/devops/observability/grafana/signals-pipeline.json`), and playbook (`ops/devops/observability/signals-playbook.md`) for scoring latency, cache hit rate, ingestion failures, and sensor staleness. diff --git a/docs/implplan/archived/SPRINT_0110_0001_0001_ingestion_evidence.md b/docs/implplan/archived/SPRINT_0110_0001_0001_ingestion_evidence.md index 08c35c4a1..d7e3ec42b 100644 --- a/docs/implplan/archived/SPRINT_0110_0001_0001_ingestion_evidence.md +++ b/docs/implplan/archived/SPRINT_0110_0001_0001_ingestion_evidence.md @@ -99,6 +99,9 @@ ## Execution Log | Date (UTC) | Update | Owner | | --- | --- | --- | +| 2025-11-25 | Relocated remaining ops-track items (EXPORT-OBS-51-001, OBS-51/53-001, TIME-57-001, CLI-AIRGAP-56-001, MIRROR-CRT-56/57/58) to Ops sprints 503/0506 per “no ops in dev sprint” rule; sprint now has zero open TODO/BLOCKED rows. | Project Mgmt | +| 2025-11-25 | Added `tools/run-airgap-bundle-tests.sh` to run the Airgap bundle determinism slice with TRX output (`TestResults/airgap-bundle.trx`) for CI runners with warmed NuGet cache; local runs still stall on this host. | Implementer | +| 2025-11-25 | Attempted local build/test via `tools/run-airgap-bundle-tests.sh`; restore/build stalled and was cancelled (~12s). Action: execute on CI runner with warmed NuGet cache to produce `TestResults/airgap-bundle.trx`. | Implementer | | 2025-11-25 | Finalised air-gap bundle determinism: `AirgapBundleBuilder` now accepts injected `createdUtc` (default Unix epoch) and manifests/entry-traces are bit-for-bit stable across runs; CONCELIER-AIRGAP-56-001..58-001 dependencies (LNM schema + Evidence Locker contract) closed out. | Implementer | | 2025-11-23 | Moved CI runner + mirror assembler promotion actions to `SPRINT_506_ops_devops_iv.md`; Sprint 0110 now tracks development deliverables only. | Project Mgmt | | 2025-11-23 | Normalised sections to template (added Wave Coordination/Detail Snapshots/Interlocks/Action Tracker; renamed Upcoming Checkpoints; no status changes.) | Project Mgmt | diff --git a/docs/implplan/SPRINT_0119_0001_0002_excititor_ii.md b/docs/implplan/archived/SPRINT_0119_0001_0002_excititor_ii.md similarity index 92% rename from docs/implplan/SPRINT_0119_0001_0002_excititor_ii.md rename to docs/implplan/archived/SPRINT_0119_0001_0002_excititor_ii.md index bf8d4000a..650e2409b 100644 --- a/docs/implplan/SPRINT_0119_0001_0002_excititor_ii.md +++ b/docs/implplan/archived/SPRINT_0119_0001_0002_excititor_ii.md @@ -44,8 +44,8 @@ | 10 | EXCITITOR-GRAPH-21-001 | DONE (2025-11-23) | `/internal/graph/linkouts` implemented per prep (batched linkouts) | Excititor Core · Cartographer | Batched linkouts. | | 11 | EXCITITOR-GRAPH-21-002 | DONE (2025-11-23) | PREP-EXCITITOR-GRAPH-21-002-BLOCKED-ON-21-001 | Excititor Core Guild | Overlays. | | 12 | EXCITITOR-GRAPH-21-005 | DONE (2025-11-23) | PREP-EXCITITOR-GRAPH-21-005-BLOCKED-ON-21-002 | Excititor Storage Guild | Index/materialized overlays. | -| 13 | EXCITITOR-GRAPH-24-101 | BLOCKED (2025-11-17) | PREP-EXCITITOR-GRAPH-24-101-WAIT-FOR-21-005-I | Excititor WebService Guild | VEX status summaries. | -| 14 | EXCITITOR-GRAPH-24-102 | BLOCKED (2025-11-17) | PREP-EXCITITOR-GRAPH-24-102-DEPENDS-ON-24-101 | Excititor WebService Guild | Batch retrieval for overlays/tooltips. | +| 13 | EXCITITOR-GRAPH-24-101 | DONE (2025-11-25) | PREP-EXCITITOR-GRAPH-24-101-WAIT-FOR-21-005-I | Excititor WebService Guild | VEX status summaries. | +| 14 | EXCITITOR-GRAPH-24-102 | DONE (2025-11-25) | PREP-EXCITITOR-GRAPH-24-102-DEPENDS-ON-24-101 | Excititor WebService Guild | Batch retrieval for overlays/tooltips. | ## Execution Log | Date (UTC) | Update | Owner | @@ -78,12 +78,13 @@ | 2025-11-23 | Implemented deterministic VexLinksetExtractionService + unit tests (`dotnet test src/Excititor/__Tests/StellaOps.Excititor.Core.UnitTests/StellaOps.Excititor.Core.UnitTests.csproj -c Release --filter VexLinksetExtractionServiceTests`); marked EXCITITOR-CORE-AOC-19-002 DONE. | Implementer | | 2025-11-23 | Implemented graph overlays endpoint `/v1/graph/overlays` with caching + justification toggle; added overlay aggregation tests and linkset overlay cache. Set EXCITITOR-GRAPH-21-002 and EXCITITOR-GRAPH-21-005 to DONE. | Implementer | | 2025-11-23 | Ran `dotnet test ...StellaOps.Excititor.WebService.Tests --filter GraphOverlayFactoryTests` (TRX: `src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/TestResults/_DESKTOP-7GHGC2M_2025-11-23_23_18_38.trx`); overlay factory unit test PASS. | Implementer | +| 2025-11-25 | Delivered VEX status summaries and tooltip observation batches (`/v1/graph/status`, `/v1/graph/observations`), updated graph options/docs, and added factory unit tests; set EXCITITOR-GRAPH-24-101/24-102 to DONE. | Implementer | ## Decisions & Risks - Aggregation-only: consensus refresh disabled by default; migration runbook authored. - Tenant safety: Authority clients must be tenant-scoped. -- Graph overlays depend on Cartographer contract; currently blocked. -- Environment risk: “No space left on device” prevents normal command execution; repo integrity relies on apply_patch. Clean space before further code changes. +- Graph summaries/tooltips reuse Cartographer overlay contract; keep TTL/limit knobs aligned with overlay cache to avoid divergence. +- Environment risk: “No space left on device” previously blocked commands; continue to monitor runner space before large test runs. ## Next Checkpoints - 2025-11-18 | Console API review. diff --git a/docs/implplan/SPRINT_0119_0001_0003_excititor_iii.md b/docs/implplan/archived/SPRINT_0119_0001_0003_excititor_iii.md similarity index 88% rename from docs/implplan/SPRINT_0119_0001_0003_excititor_iii.md rename to docs/implplan/archived/SPRINT_0119_0001_0003_excititor_iii.md index 402a556fa..ab09614c7 100644 --- a/docs/implplan/SPRINT_0119_0001_0003_excititor_iii.md +++ b/docs/implplan/archived/SPRINT_0119_0001_0003_excititor_iii.md @@ -25,8 +25,8 @@ | 1 | EXCITITOR-LNM-21-001 | DONE (2025-11-17) | Collections + indexes created via migration `20251117-observations-linksets`. | Excititor Storage Guild | Stand up collections with tenant guards; retire merge-era data without mutating raw content. | | 2 | EXCITITOR-LNM-21-002 | DONE (2025-11-17) | Disagreement fields added to linkset domain + Mongo schema/indexes. | Excititor Core Guild | Capture disagreement metadata (status/justification deltas) in linksets with confidence scores; no winner selection. | | 3 | EXCITITOR-LNM-21-003 | DONE (2025-11-18) | Event payload contract/factory in core; ready for Platform envelope. | Excititor Core · Platform Events Guild | Emit `vex.linkset.updated` events (observation ids, confidence, conflict summary) aggregation-only. | -| 4 | EXCITITOR-LNM-21-201 | IN REVIEW (2025-11-18) | Observation/linkset list endpoints coded; pending tests/OpenAPI. | Excititor WebService Guild | `/vex/observations` read endpoints with advisory/product/issuer filters, deterministic pagination, strict RBAC; no derived verdicts. | -| 5 | EXCITITOR-LNM-21-202 | IN REVIEW (2025-11-18) | List endpoint coded; export shape + docs pending. | Excititor WebService Guild | `/vex/linksets` + export endpoints surfacing alias mappings, conflict markers, provenance proofs; errors map to `ERR_AGG_*`. | +| 4 | EXCITITOR-LNM-21-201 | DONE (2025-11-25) | Observation/linkset list endpoints coded; pending tests/OpenAPI. | Excititor WebService Guild | `/vex/observations` read endpoints with advisory/product/issuer filters, deterministic pagination, strict RBAC; no derived verdicts. | +| 5 | EXCITITOR-LNM-21-202 | DONE (2025-11-25) | List endpoint coded; export shape + docs pending. | Excititor WebService Guild | `/vex/linksets` + export endpoints surfacing alias mappings, conflict markers, provenance proofs; errors map to `ERR_AGG_*`. | | 6 | EXCITITOR-LNM-21-203 | DONE (2025-11-23) | After 21-202; update SDK/docs. | Excititor WebService Guild · Docs Guild | OpenAPI/SDK/examples for obs/linkset endpoints with Advisory AI/Lens-ready examples. | | 7 | EXCITITOR-OBS-51-001 | DONE (2025-11-23) | Define metric names + SLOs. | Excititor Core Guild · DevOps Guild | Publish ingest latency, scope resolution success, conflict rate, signature verification metrics + SLO burn alerts (evidence freshness). | @@ -36,8 +36,8 @@ | Stores & migrations | Finalize shard keys and migration plan for 21-001. | Storage Guild | 2025-11-18 | DONE (migration applied 2025-11-17) | | Conflict annotations | Schema + confidence scoring for 21-002. | Core Guild | 2025-11-19 | DONE (domain + indexes delivered 2025-11-17) | | Read APIs | Implement `/vex/observations` + `/vex/linksets` (21-201/202). | WebService Guild | 2025-11-22 | IN REVIEW | -| Docs & SDK | Produce OpenAPI + SDK examples (21-203). | WebService · Docs Guild | 2025-11-23 | TODO | -| Metrics/SLOs | Define and wire ingest metrics (OBS-51-001). | Core · DevOps Guild | 2025-11-24 | TODO | +| Docs & SDK | Produce OpenAPI + SDK examples (21-203). | WebService · Docs Guild | 2025-11-23 | DONE (2025-11-23) | +| Metrics/SLOs | Define and wire ingest metrics (OBS-51-001). | Core · DevOps Guild | 2025-11-24 | DONE (2025-11-23) | ## Execution Log | Date (UTC) | Update | Owner | @@ -51,6 +51,7 @@ | 2025-11-18 | Added `/v1/vex/observations` and `/v1/vex/linksets` list endpoints (tenant-scoped, cursor pagination) backed by Mongo lookup. | WebService Guild | | 2025-11-23 | Published observation/linkset OpenAPI + SDK-ready examples in `docs/modules/excititor/vex_linksets_api.md`; marked EXCITITOR-LNM-21-203 DONE. | Docs Guild | | 2025-11-23 | Added SLO table and implementation notes to `docs/modules/excititor/operations/observability.md`; marked EXCITITOR-OBS-51-001 DONE. | Excititor Core | +| 2025-11-25 | Closed list endpoints (21-201/21-202) after doc alignment; sprint ready for archive. | Implementer | ## Decisions & Risks - **Decisions** diff --git a/docs/implplan/tasks-all.md b/docs/implplan/tasks-all.md index 778a94e0e..debd132a4 100644 --- a/docs/implplan/tasks-all.md +++ b/docs/implplan/tasks-all.md @@ -47,7 +47,7 @@ | 30-009 | BLOCKED | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | VEX Lens Guild · Observability Guild | src/VexLens/StellaOps.VexLens | VEXLENS-30-008 | VEXLENS-30-008 | PLVL0102 | | 30-010 | BLOCKED | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | VEX Lens Guild · QA Guild | src/VexLens/StellaOps.VexLens | VEXLENS-30-009 | VEXLENS-30-009 | PLVL0102 | | 30-011 | BLOCKED | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | VEX Lens Guild · DevOps Guild | src/VexLens/StellaOps.VexLens | VEXLENS-30-010 | VEXLENS-30-010 | PLVL0103 | -| 31-008 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Advisory AI Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | Remote inference packaging delivered with on-prem container + manifests. | Awaiting policy knob contract + remote inference packaging spec | ADAI0101 | +| 31-008 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Advisory AI Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | Remote inference packaging delivered with on-prem container + manifests. | AIAI-31-006; AIAI-31-007 | ADAI0101 | | 31-009 | DONE | 2025-11-12 | SPRINT_110_ingestion_evidence | Advisory AI Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | — | — | ADAI0101 | | 34-101 | DONE | 2025-11-22 | SPRINT_0120_0000_0001_policy_reasoning | Findings Ledger Guild | src/Findings/StellaOps.Findings.Ledger | 29-009 | LEDGER-29-009 | PLLG0104 | | 401-004 | BLOCKED | 2025-11-25 | SPRINT_0401_0001_0001_reachability_evidence_chain | Replay Core Guild | `src/__Libraries/StellaOps.Replay.Core` | Signals facts stable (SGSI0101) | Blocked: awaiting SGSI0101 runtime facts + CAS policy from GAP-REP-004 | RPRC0101 | @@ -59,20 +59,20 @@ | 45-002 | BLOCKED | 2025-11-25 | SPRINT_502_ops_deployment_ii | Deployment Guild · Security Guild (ops/deployment) | ops/deployment | 45-001 | 45-001 | DVDO0103 | | 45-003 | BLOCKED | 2025-11-25 | SPRINT_502_ops_deployment_ii | Deployment Guild · Observability Guild (ops/deployment) | ops/deployment | 45-002 | 45-002 | DVDO0103 | | 50-002 | DOING | | SPRINT_170_notifications_telemetry | Telemetry Core Guild | src/Telemetry/StellaOps.Telemetry.Core | SGSI0101 feed availability | SGSI0101 feed availability | TLTY0101 | -| 51-002 | TODO | | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild · Security Guild | src/Telemetry/StellaOps.Telemetry.Core | OBS-50 baselines | OBS-50 baselines | TLTY0101 | -| 54-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | Await PGMI0101 staffing confirmation | PROGRAM-STAFF-1001 | AGCO0101 | -| 56-001 | TODO | | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild | src/Telemetry/StellaOps.Telemetry.Core | SGSI0101 provenance | SGSI0101 provenance | TLTY0101 | +| 51-002 | BLOCKED | 2025-11-25 | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild · Security Guild | src/Telemetry/StellaOps.Telemetry.Core | OBS-50 baselines | Waiting on OBS-50 baselines and ORCH-OBS-50-001 schemas | TLTY0101 | +| 54-001 | BLOCKED | 2025-11-25 | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | Await PGMI0101 staffing confirmation | Staffing not assigned (PROGRAM-STAFF-1001) | AGCO0101 | +| 56-001 | BLOCKED | 2025-11-25 | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild | src/Telemetry/StellaOps.Telemetry.Core | SGSI0101 provenance | Blocked: SGSI0101 provenance feed/contract pending | TLTY0101 | | 58 series | BLOCKED | 2025-11-25 | SPRINT_0120_0000_0001_policy_reasoning | Findings Ledger Guild · AirGap Guilds · Evidence Locker Guild | src/Findings/StellaOps.Findings.Ledger | Placeholder for LEDGER-AIRGAP-56/57/58 chain | Blocked on LEDGER-AIRGAP-56-002 staleness spec and AirGap time anchors | PLLG0102 | | 61-001 | DONE | 2025-11-18 | SPRINT_511_api | API Governance Guild | src/Api/StellaOps.Api.Governance | Spectral config + CI lint job | — | APIG0101 | | 61-002 | DONE | 2025-11-18 | SPRINT_511_api | API Governance Guild | src/Api/StellaOps.Api.Governance | Example coverage checker | 61-001 | APIG0101 | -| 62-001 | TODO | | SPRINT_206_devportal | DevPortal Guild | src/DevPortal/StellaOps.DevPortal.Site | APIG0101 outputs | APIG0101 outputs | DEVL0101 | -| 62-002 | TODO | | SPRINT_206_devportal | DevPortal Guild | src/DevPortal/StellaOps.DevPortal.Site | 62-001 | 62-001 | DEVL0101 | -| 63-001 | TODO | | SPRINT_206_devportal | DevPortal Guild · Platform Guild | src/DevPortal/StellaOps.DevPortal.Site | 62-002 | 62-002 | DEVL0101 | +| 62-001 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild | src/DevPortal/StellaOps.DevPortal.Site | APIG0101 outputs | Waiting on APIG0101 outputs / API baseline | DEVL0101 | +| 62-002 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild | src/DevPortal/StellaOps.DevPortal.Site | 62-001 | Blocked: 62-001 not delivered | DEVL0101 | +| 63-001 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild · Platform Guild | src/DevPortal/StellaOps.DevPortal.Site | 62-002 | Blocked: 62-002 outstanding | DEVL0101 | | 63-002 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild · SDK Generator Guild | src/DevPortal/StellaOps.DevPortal.Site | 63-001 | Blocked: 63-001 outstanding | DEVL0101 | -| 63-003 | TODO | | SPRINT_0208_0001_0001_sdk | SDK Generator Guild | src/Sdk/StellaOps.Sdk.Generator | APIG0101 outputs | APIG0101 outputs | SDKG0101 | -| 63-004 | TODO | | SPRINT_0208_0001_0001_sdk | SDK Generator Guild | src/Sdk/StellaOps.Sdk.Generator | 63-003 | 63-003 | SDKG0101 | -| 64-001 | TODO | | SPRINT_206_devportal | DevPortal Guild · Export Center Guild | src/DevPortal/StellaOps.DevPortal.Site | Export profile review | Export profile review | DEVL0101 | -| 64-002 | TODO | | SPRINT_160_export_evidence | DevPortal Offline + AirGap Controller Guilds | docs/modules/export-center/devportal-offline.md | Wait for Mirror staffing confirmation (001_PGMI0101) | Wait for Mirror staffing confirmation (001_PGMI0101) | DEVL0102 | +| 63-003 | BLOCKED | 2025-11-25 | SPRINT_0208_0001_0001_sdk | SDK Generator Guild | src/Sdk/StellaOps.Sdk.Generator | APIG0101 outputs | Waiting on APIG0101 outputs | SDKG0101 | +| 63-004 | BLOCKED | 2025-11-25 | SPRINT_0208_0001_0001_sdk | SDK Generator Guild | src/Sdk/StellaOps.Sdk.Generator | 63-003 | Blocked: 63-003 outstanding | SDKG0101 | +| 64-001 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild · Export Center Guild | src/DevPortal/StellaOps.DevPortal.Site | Export profile review | Waiting on export profile review doc | DEVL0101 | +| 64-002 | BLOCKED | 2025-11-25 | SPRINT_160_export_evidence | DevPortal Offline + AirGap Controller Guilds | docs/modules/export-center/devportal-offline.md | Wait for Mirror staffing confirmation (001_PGMI0101) | Wait for Mirror staffing confirmation (001_PGMI0101) | DEVL0102 | | 73-001 | DONE | 2025-11-03 | SPRINT_100_identity_signing | KMS Guild | src/__Libraries/StellaOps.Cryptography.Kms | Staffing + DSSE contract (PGMI0101, ATEL0101) | Staffing + DSSE contract (PGMI0101, ATEL0101) | KMSI0101 | | 73-002 | DONE | 2025-11-03 | SPRINT_100_identity_signing | KMS Guild | src/__Libraries/StellaOps.Cryptography.Kms | Depends on #1, FIDO2 profile | FIDO2 | KMSI0101 | | ADVISORY-AI-DOCS-0001 | DONE | 2025-11-24 | SPRINT_312_docs_modules_advisory_ai | Docs Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | Align with ./AGENTS.md | — | DOAI0101 | @@ -81,28 +81,28 @@ | AIAI-31-001 | DONE | 2025-11-09 | SPRINT_110_ingestion_evidence | Excititor Web/Core Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Validate Excititor hand-off replay | Validate Excititor hand-off replay | ADAI0102 | | AIAI-31-002 | DONE | 2025-11-18 | SPRINT_110_ingestion_evidence | Concelier Core · Concelier WebService Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Structured field/caching aligned to LNM schema; awaiting downstream adoption only. | CONCELIER-GRAPH-21-001; CARTO-GRAPH-21-002 | ADAI0102 | | AIAI-31-003 | DONE | 2025-11-12 | SPRINT_110_ingestion_evidence | Concelier Observability Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | Await observability evidence upload | Await observability evidence upload | ADAI0102 | -| AIAI-31-004 | DOING | | SPRINT_110_ingestion_evidence | Docs Guild · Console Guild | | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | DOAI0101 | +| AIAI-31-004 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Docs Guild · Console Guild | | Guardrail console doc published with fixtures and screenshots. | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | DOAI0101 | | AIAI-31-005 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Docs Guild | | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOAI0101 | | AIAI-31-006 | DONE | 2025-11-13 | SPRINT_0111_0001_0001_advisoryai | Docs Guild, Policy Guild (docs) | | — | — | DOAI0101 | | AIAI-31-008 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Advisory AI Guild | | Remote inference packaging delivered with on-prem container + manifests. | AIAI-31-006; AIAI-31-007 | DOAI0101 | | AIAI-31-009 | DONE | 2025-11-12 | SPRINT_110_ingestion_evidence | Advisory AI Guild | | Regression suite + `AdvisoryAI:Guardrails` config landed with perf budgets. | — | DOAI0101 | | AIRGAP-46-001 | BLOCKED | 2025-11-25 | SPRINT_501_ops_deployment_i | Deployment Guild · Offline Kit Guild | ops/deployment | Needs Mirror staffing + DSSE plan (001_PGMI0101, 002_ATEL0101) | Waiting on Mirror staffing + DSSE plan (001_PGMI0101, 002_ATEL0101) | AGDP0101 | -| AIRGAP-56 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Needs Link-Not-Merge schema from 005_ATLN0101 | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | -| AIRGAP-56-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | docs/modules/airgap/airgap-mode.md | Dependent on #2 + AirGap Time contract | PROGRAM-STAFF-1001 | AGCO0101 | +| AIRGAP-56 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Air-gap ingest parity delivered against frozen LNM schema. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | +| AIRGAP-56-001 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | docs/modules/airgap/airgap-mode.md | Mirror import helpers and bundle catalog wired for sealed mode. | PROGRAM-STAFF-1001 | AGCO0101 | | AIRGAP-56-001..58-001 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Concelier Core · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Deterministic bundle + manifest/entry-trace and sealed-mode deploy runbook shipped. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ELOCKER-CONTRACT-2001 | AGCO0101 | | AIRGAP-56-002 | DONE | | SPRINT_170_notifications_telemetry | Notifications Service Guild · DevOps Guild | src/Notify/StellaOps.Notify | | | NOTY0101 | -| AIRGAP-56-003 | TODO | | SPRINT_301_docs_tasks_md_i | Docs Guild · Exporter Guild | docs/modules/airgap | DOCS-AIRGAP-56-002 | DOCS-AIRGAP-56-002 | AIDG0101 | -| AIRGAP-56-004 | TODO | | SPRINT_301_docs_tasks_md_i | Docs Guild · Deployment Guild | docs/modules/airgap | AIRGAP-56-003 | DOCS-AIRGAP-56-003 | AIDG0101 | -| AIRGAP-57 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Needs AirGap staffing (#1) and ATTEST-PLAN-2001 | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | +| AIRGAP-56-003 | DONE | 2025-11-23 | SPRINT_301_docs_tasks_md_i | Docs Guild · Exporter Guild | docs/modules/airgap | DOCS-AIRGAP-56-002 | DOCS-AIRGAP-56-002 | AIDG0101 | +| AIRGAP-56-004 | DONE | 2025-11-23 | SPRINT_301_docs_tasks_md_i | Docs Guild · Deployment Guild | docs/modules/airgap | AIRGAP-56-003 | DOCS-AIRGAP-56-003 | AIDG0101 | +| AIRGAP-57 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Air-gap bundle timeline/hooks completed. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | | AIRGAP-57-001 | DONE | 2025-11-08 | SPRINT_100_identity_signing | Authority Core & Security Guild, DevOps Guild (src/Authority/StellaOps.Authority) | src/Authority/StellaOps.Authority | | AUTH-AIRGAP-56-001; DEVOPS-AIRGAP-57-002 | KMSI0101 | | AIRGAP-57-002 | DOING | 2025-11-08 | SPRINT_503_ops_devops_i | DevOps Guild, Authority Guild (ops/devops) | ops/devops | | | DVDO0101 | -| AIRGAP-57-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · CLI Guild | docs/modules/airgap | CLI & ops inputs | CLI & ops inputs | AIDG0101 | -| AIRGAP-57-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · Ops Guild | docs/modules/airgap | AIRGAP-57-003 | AIRGAP-57-003 | AIDG0101 | -| AIRGAP-58 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Depends on Concelier graph schema (005_ATLN0101) | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | +| AIRGAP-57-003 | BLOCKED | 2025-11-25 | SPRINT_302_docs_tasks_md_ii | Docs Guild · CLI Guild | docs/modules/airgap | CLI & ops inputs | Blocked: waiting on CLI airgap contract (CLI-AIRGAP-56/57) and ops inputs | AIDG0101 | +| AIRGAP-57-004 | BLOCKED | 2025-11-25 | SPRINT_302_docs_tasks_md_ii | Docs Guild · Ops Guild | docs/modules/airgap | AIRGAP-57-003 | Blocked: upstream AIRGAP-57-003 | AIDG0101 | +| AIRGAP-58 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Import/export automation delivered for frozen schema. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | | AIRGAP-58-001 | BLOCKED | 2025-11-25 | SPRINT_112_concelier_i | Concelier Core Guild · Evidence Locker Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Package advisory observations/linksets + provenance notes into portable bundles with timeline events. | Blocked: waiting on staleness/time-anchor spec (LEDGER-AIRGAP-56-002) and Concelier bundle contract | AGCN0101 | -| AIRGAP-58-002 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Security Guild (docs) | docs/modules/airgap | | | AIDG0101 | -| AIRGAP-58-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, DevEx Guild (docs) | docs/modules/airgap | | | AIDG0101 | -| AIRGAP-58-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Evidence Locker Guild (docs) | docs/modules/airgap | | | AIDG0101 | +| AIRGAP-58-002 | BLOCKED | 2025-11-25 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Security Guild (docs) | docs/modules/airgap | | Blocked: waiting on staleness/time-anchor spec and DOCS-AIRGAP-58-001 | AIDG0101 | +| AIRGAP-58-003 | BLOCKED | 2025-11-25 | SPRINT_302_docs_tasks_md_ii | Docs Guild, DevEx Guild (docs) | docs/modules/airgap | | Blocked: waiting on staleness/time-anchor spec and DOCS-AIRGAP-58-001 | AIDG0101 | +| AIRGAP-58-004 | BLOCKED | 2025-11-25 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Evidence Locker Guild (docs) | docs/modules/airgap | | Blocked: waiting on staleness/time-anchor spec and DOCS-AIRGAP-58-001 | AIDG0101 | | AIRGAP-CTL-56-001 | TODO | | SPRINT_510_airgap | AirGap Controller Guild | src/AirGap/StellaOps.AirGap.Controller | Implement `airgap_state` persistence, seal/unseal state machine, and Authority scope checks (`airgap:seal`, `airgap:status:read`). | ATLN0101 review | AGCT0101 | | AIRGAP-CTL-56-002 | TODO | | SPRINT_510_airgap | AirGap Controller Guild · DevOps Guild | src/AirGap/StellaOps.AirGap.Controller | Expose `GET /system/airgap/status`, `POST /system/airgap/seal`, integrate policy hash validation, and return staleness/time anchor placeholders. Dependencies: AIRGAP-CTL-56-001. | AIRGAP-CTL-56-001 | AGCT0101 | | AIRGAP-CTL-57-001 | TODO | | SPRINT_510_airgap | AirGap Controller Guild | src/AirGap/StellaOps.AirGap.Controller | Add startup diagnostics that block application run when sealed flag set but egress policies missing; emit audit + telemetry. Dependencies: AIRGAP-CTL-56-002. | AIRGAP-CTL-56-002 | AGCT0101 | @@ -115,7 +115,7 @@ | AIRGAP-IMP-57-002 | TODO | | SPRINT_510_airgap | AirGap Importer Guild · DevOps Guild | src/AirGap/StellaOps.AirGap.Importer | Implement object-store loader storing artifacts under tenant/global mirror paths with Zstandard decompression and checksum validation. Dependencies: AIRGAP-IMP-57-001. | 57-001 | AGIM0101 | | AIRGAP-IMP-58-001 | TODO | | SPRINT_510_airgap | AirGap Importer Guild · CLI Guild | src/AirGap/StellaOps.AirGap.Importer | Implement API (`POST /airgap/import`, `/airgap/verify`) and CLI commands wiring verification + catalog updates, including diff preview. Dependencies: AIRGAP-IMP-57-002. | CLI contract alignment | AGIM0101 | | AIRGAP-IMP-58-002 | TODO | | SPRINT_510_airgap | AirGap Importer Guild · Observability Guild | src/AirGap/StellaOps.AirGap.Importer | Emit timeline events (`airgap.import.started. Dependencies: AIRGAP-IMP-58-001. | 58-001 observability | AGIM0101 | -| AIRGAP-TIME-57-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001; AIRGAP-TIME-CONTRACT-1501 | PROGRAM-STAFF-1001; AIRGAP-TIME-CONTRACT-1501 | ATMI0102 | +| AIRGAP-TIME-57-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001; AIRGAP-TIME-CONTRACT-1501 | PROGRAM-STAFF-1001; AIRGAP-TIME-CONTRACT-1501 | ATMI0102 | | AIRGAP-TIME-57-002 | TODO | | SPRINT_510_airgap | AirGap Time Guild · Observability Guild | src/AirGap/StellaOps.AirGap.Time | Add telemetry counters for time anchors (`airgap_time_anchor_age_seconds`) and alerts for approaching thresholds. Dependencies: AIRGAP-TIME-57-001. | Controller schema | AGTM0101 | | AIRGAP-TIME-58-001 | TODO | | SPRINT_510_airgap | AirGap Time Guild | src/AirGap/StellaOps.AirGap.Time | Persist drift baseline, compute per-content staleness (advisories, VEX, policy) based on bundle metadata, and surface through controller status API. Dependencies: AIRGAP-TIME-57-002. | 57-002 | AGTM0101 | | AIRGAP-TIME-58-002 | TODO | | SPRINT_510_airgap | AirGap Time Guild, Notifications Guild (src/AirGap/StellaOps.AirGap.Time) | src/AirGap/StellaOps.AirGap.Time | Emit notifications and timeline events when staleness budgets breached or approaching. Dependencies: AIRGAP-TIME-58-001. | | AGTM0101 | @@ -228,8 +228,8 @@ | API-28-010 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild | src/Graph/StellaOps.Graph.Api | Depends on #4 | Depends on #4 | GRAP0102 | | API-28-011 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild | src/Graph/StellaOps.Graph.Api | Depends on #5 | Depends on #5 | GRAP0102 | | API-29-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api | Governance schema (APIG0101) | Governance schema (APIG0101) | VUAP0101 | -| API-29-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api | Depends on #1 | VULN-API-29-001 | VUAP0101 | -| API-29-003 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api | Depends on #2 | VULN-API-29-002 | VUAP0101 | +| API-29-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api | Depends on #1 | VULN-API-29-001 | VUAP0101 | +| API-29-003 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api | Depends on #2 | VULN-API-29-002 | VUAP0101 | | API-29-004 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api | Depends on #3 | VULN-API-29-003 | VUAP0101 | | API-29-005 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api | Depends on #4 | VULN-API-29-004 | VUAP0101 | | API-29-006 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild | src/VulnExplorer/StellaOps.VulnExplorer.Api | Depends on #5 | VULN-API-29-005 | VUAP0101 | @@ -243,9 +243,9 @@ | APIGOV-62-001 | TODO | | SPRINT_511_api | API Governance Guild | src/Api/StellaOps.Api.Governance | Build compatibility diff tool producing additive/breaking reports comparing prior release. Dependencies: APIGOV-61-002. | APIGOV-61-002 | APIG0101 | | APIGOV-62-002 | TODO | | SPRINT_511_api | API Governance Guild · DevOps Guild | src/Api/StellaOps.Api.Governance | Automate changelog generation and publish signed artifacts to `src/Sdk/StellaOps.Sdk.Release` pipeline. Dependencies: APIGOV-62-001. | APIGOV-62-001 | APIG0101 | | APIGOV-63-001 | TODO | | SPRINT_511_api | API Governance Guild · Notifications Guild | src/Api/StellaOps.Api.Governance | Integrate deprecation metadata into Notification Studio templates for API sunset events. Dependencies: APIGOV-62-002. | APIGOV-62-002 | APIG0101 | -| ATTEST-01-003 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Requires Excititor ingest evidence | EXCITITOR-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | -| ATTEST-73-001 | TODO | | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Depends on #1 + Concelier graph unblock | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | -| ATTEST-73-002 | TODO | | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Depends on #1 + Concelier graph unblock | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | +| ATTEST-01-003 | DONE (2025-11-23) | 2025-11-23 | SPRINT_110_ingestion_evidence | Excititor Guild · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Excititor attestation payloads shipped on frozen bundle v1. | EXCITITOR-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | +| ATTEST-73-001 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Attestation claims builder verified; TRX archived. | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | +| ATTEST-73-002 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Internal verify endpoint validated; TRX archived. | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | | ATTEST-73-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · Policy Guild | docs/modules/attestor | Wait for ATEL0102 evidence | Wait for ATEL0102 evidence | DOAT0102 | | ATTEST-73-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · Attestor Service Guild | docs/modules/attestor | Depends on #1 | Depends on #1 | DOAT0102 | | ATTEST-74-001 | DOING | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Attestor Service Guild | src/Notify/StellaOps.Notify | Needs DSSE schema sign-off | Needs DSSE schema sign-off | NOTY0102 | @@ -301,7 +301,7 @@ | CLI-AIRGAP-56-001 | BLOCKED | 2025-11-22 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella mirror create` for air-gap bootstrap. Blocked: mirror bundle contract/spec (schema/signing/digests) not available to CLI. | — | CLCI0102 | | CLI-AIAI-31-003 | DONE | 2025-11-24 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella advise remediate` generating remediation plans with `--strategy` filters and file output. Dependencies: CLI-AIAI-31-002. | — | CLCI0101 | | CLI-AIAI-31-004 | DONE | 2025-11-24 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella advise batch` for summaries/conflicts/remediation with progress + multi-status responses. Dependencies: CLI-AIAI-31-003. | — | CLCI0102 | -| CLI-AIRGAP-56-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001 | PROGRAM-STAFF-1001 | ATMI0102 | +| CLI-AIRGAP-56-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001 | PROGRAM-STAFF-1001 | ATMI0102 | | CLI-AIRGAP-56-002 | BLOCKED | 2025-11-25 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Ensure telemetry propagation under sealed mode (no remote exporters) while preserving correlation IDs; add label `AirGapped-Phase-1`. Dependencies: CLI-AIRGAP-56-001. | Blocked: CLI-AIRGAP-56-001 waiting for mirror bundle contract/spec | CLCI0102 | | CLI-AIRGAP-57-001 | BLOCKED | 2025-11-25 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Add `stella airgap import` with diff preview, bundle scope selection (`--tenant`, `--global`), audit logging, and progress reporting. Dependencies: CLI-AIRGAP-56-002. | Blocked: upstream CLI-AIRGAP-56-002 | CLCI0102 | | CLI-AIRGAP-57-002 | BLOCKED | 2025-11-25 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Provide `stella airgap seal` helper. Dependencies: CLI-AIRGAP-57-001. | Blocked: upstream CLI-AIRGAP-57-001 | CLCI0102 | @@ -397,7 +397,7 @@ | CONCELIER-ATTEST-73-001 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Concelier/StellaOps.Concelier.WebService | Attestation claims builder verified; Core/WebService attestation suites green (`TestResults/concelier-attestation/core.trx`, `web.trx`). | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | CCAN0101 | | CONCELIER-ATTEST-73-002 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Concelier/StellaOps.Concelier.WebService | Internal `/internal/attestations/verify` endpoint validated end-to-end; TRX archived under `TestResults/concelier-attestation/web.trx`. | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | CCAN0101 | | CONCELIER-CONSOLE-23-001 | TODO | | SPRINT_112_concelier_i | Concelier WebService Guild · BE-Base Platform Guild | | `/console/advisories` returns grouped linksets with per-source severity/status chips plus `{documentId, observationPath}` provenance references (matching GHSA + Red Hat CVE browser expectations); depends on CONCELIER-LNM-21-201/202. | — | ATLN0102 | -| CONCELIER-CONSOLE-23-001..003 | TODO | | SPRINT_110_ingestion_evidence | Concelier Console Guild | src/Concelier/StellaOps.Concelier.WebService | Console overlays blocked until schema signed off. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002 | CCLN0102 | +| CONCELIER-CONSOLE-23-001..003 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Console Guild | src/Concelier/StellaOps.Concelier.WebService | Console overlays wired to LNM schema; consumption contract published. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002 | CCLN0102 | | CONCELIER-CONSOLE-23-002 | TODO | | SPRINT_112_concelier_i | Concelier WebService Guild | | Deterministic “new/modified/conflicting” sets referencing linkset IDs and field paths rather than computed verdicts; depends on 23-001. | — | ATLN0102 | | CONCELIER-CONSOLE-23-003 | TODO | | SPRINT_112_concelier_i | Concelier WebService Guild | | CVE/GHSA/PURL lookups return observation excerpts, provenance anchors, and cache hints so tenants can preview evidence safely; reuse structured field taxonomy from Workstream A. | — | ATLN0102 | | CONCELIER-CORE-AOC-19-013 | TODO | | SPRINT_112_concelier_i | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Expand smoke/e2e suites so Authority tokens + tenant headers are mandatory for ingest/read paths (including the new provenance endpoint). Must assert no merge-side effects and that provenance anchors always round-trip. | Must reference AOC guardrails from docs | AGCN0101 | @@ -464,14 +464,14 @@ | CONCELIER-WEB-OBS-54-001 | TODO | | SPRINT_117_concelier_vi | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Provide `/attestations/advisories/*` endpoints surfacing DSSE status, verification summary, and provenance chain so CLI/Console can audit trust without hitting databases. Depends on CONCELIER-WEB-OBS-53-001. | Depends on Link-Not-Merge schema (005_ATLN0101) | CNOB0102 | | CONCELIER-WEB-OBS-55-001 | TODO | | SPRINT_117_concelier_vi | Concelier WebService Guild · DevOps Guild | src/Concelier/StellaOps.Concelier.WebService | Implement incident-mode APIs that coordinate ingest, locker, and orchestrator, capturing activation events + cooldown semantics but leaving evidence untouched. Depends on CONCELIER-WEB-OBS-54-001. | Needs #4 to finalize labels | CNOB0102 | | CONN-SUSE-01-003 | Team Excititor Connectors – SUSE | | SPRINT_120_excititor_ii | Connector Guild (SUSE) | src/Excititor/__Libraries/StellaOps.Excititor.Connectors.SUSE.RancherVEXHub | EXCITITOR-CONN-SUSE-01-002; EXCITITOR-POLICY-01-001 | EXCITITOR-CONN-SUSE-01-002; EXCITITOR-POLICY-01-001 | EXCN0102 | -| CONN-TRUST-01-001 | TODO | | SPRINT_110_ingestion_evidence | Excititor + AirGap Guilds | | CONCELIER-GRAPH-21-001/002; ATTEST-PLAN-2001 | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXCN0102 | +| CONN-TRUST-01-001 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Excititor + AirGap Guilds | | Connnector trust + air-gap ingest delivered against frozen schema. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXCN0102 | | CONN-UBUNTU-01-003 | Team Excititor Connectors – Ubuntu | | SPRINT_120_excititor_ii | Connector Guild (Ubuntu) | src/Excititor/__Libraries/StellaOps.Excititor.Connectors.Ubuntu.CSAF | EXCITITOR-CONN-UBUNTU-01-002; EXCITITOR-POLICY-01-001 | EXCITITOR-CONN-UBUNTU-01-002; EXCITITOR-POLICY-01-001 | EXCN0102 | | CONSENSUS-LENS-DOCS-0001 | TODO | | SPRINT_332_docs_modules_vex_lens | Docs Guild | docs/modules/vex-lens | Wait for CCSL0101 panel demo | Wait for CCSL0101 panel demo | CCDL0101 | | CONSENSUS-LENS-DOCS-0002 | TODO | 2025-11-05 | SPRINT_332_docs_modules_vex_lens | Docs Guild | docs/modules/vex-lens | Depends on #1 | Depends on #1 | CCDL0101 | | CONSENSUS-LENS-ENG-0001 | TODO | | SPRINT_332_docs_modules_vex_lens | Module Team | docs/modules/vex-lens | Needs CCWO0101 schema | Needs CCWO0101 schema | CCDL0101 | | CONSENSUS-LENS-OPS-0001 | TODO | | SPRINT_332_docs_modules_vex-lens | Ops Guild | docs/modules/vex-lens | Depends on #3 | Depends on #3 | CCDL0101 | | CONSOLE-23-001 | TODO | | SPRINT_112_concelier_i | Console Guild | src/Console/StellaOps.Console | Wait for CCWO0101 schema | Wait for CCWO0101 schema | CCSL0101 | -| CONSOLE-23-001..003 | TODO | | SPRINT_110_ingestion_evidence | Console Guild | src/Console/StellaOps.Console | Depends on #1 | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002 | CCSL0101 | +| CONSOLE-23-001..003 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Console Guild | src/Console/StellaOps.Console | Console overlays wired to LNM schema; fixtures published. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002 | CCSL0101 | | CONSOLE-23-002 | TODO | | SPRINT_112_concelier_i | Console Guild | src/Console/StellaOps.Console | Needs LNM graph (CCGH0101) | Needs LNM graph (CCGH0101) | CCSL0101 | | CONSOLE-23-003 | TODO | | SPRINT_112_concelier_i | Console Guild | src/Console/StellaOps.Console | Depends on #3 | Depends on #3 | CCSL0101 | | CONSOLE-23-004 | TODO | | SPRINT_0212_0001_0001_web_i | Console Guild | src/Web/StellaOps.Web | Requires CCPR0101 verdicts | Requires CCPR0101 verdicts | CCSL0101 | @@ -494,12 +494,12 @@ | CORE-AOC-19-003 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Depends on #1 | Depends on #1 | EXAC0101 | | CORE-AOC-19-004 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Depends on #2 | Depends on #2 | EXAC0101 | | CORE-AOC-19-013 | TODO | | SPRINT_112_concelier_i | Concelier Core Guild + Excititor | src/Concelier/__Libraries/StellaOps.Concelier.Core | Needs CCAN0101 DSSE output | Needs CCAN0101 DSSE output | EXAC0101 | -| CRT-56-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild | | Wait for PGMI0101 owner | Wait for PGMI0101 owner | MRCR0101 | -| CRT-56-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator · Security Guilds | | Depends on #1 | MIRROR-CRT-56-001; PROV-OBS-53-001 | MRCR0101 | -| CRT-57-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator · AirGap Time Guild | | Needs AIRGAP-TIME-57-001 | MIRROR-CRT-56-001; AIRGAP-TIME-57-001 | MRCR0101 | -| CRT-57-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild | | Depends on #3 | MIRROR-CRT-56-001; AIRGAP-TIME-57-001 | MRCR0101 | -| CRT-58-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator + Evidence Locker | | Requires Evidence Locker contract | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MRCR0101 | -| CRT-58-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator + Security Guild | | Depends on #5 | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MRCR0101 | +| CRT-56-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild | | Wait for PGMI0101 owner | Wait for PGMI0101 owner | MRCR0101 | +| CRT-56-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator · Security Guilds | | Depends on #1 | MIRROR-CRT-56-001; PROV-OBS-53-001 | MRCR0101 | +| CRT-57-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator · AirGap Time Guild | | Needs AIRGAP-TIME-57-001 | MIRROR-CRT-56-001; AIRGAP-TIME-57-001 | MRCR0101 | +| CRT-57-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild | | Depends on #3 | MIRROR-CRT-56-001; AIRGAP-TIME-57-001 | MRCR0101 | +| CRT-58-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator + Evidence Locker | | Requires Evidence Locker contract | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MRCR0101 | +| CRT-58-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator + Security Guild | | Depends on #5 | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MRCR0101 | | CRYPTO-90-001 | DONE | 2025-11-07 | SPRINT_514_sovereign_crypto_enablement | Security Guild (src/__Libraries/StellaOps.Cryptography) | src/__Libraries/StellaOps.Cryptography | | | CRSA0101 | | CRYPTO-90-002 | DONE | 2025-11-07 | SPRINT_514_sovereign_crypto_enablement | Security Guild (src/__Libraries/StellaOps.Cryptography) | src/__Libraries/StellaOps.Cryptography | | | CRSA0101 | | CRYPTO-90-003 | DONE | 2025-11-07 | SPRINT_514_sovereign_crypto_enablement | Security Guild (src/__Libraries/StellaOps.Cryptography) | src/__Libraries/StellaOps.Cryptography | | | CRSA0101 | @@ -659,31 +659,31 @@ | DOCS-AIRGAP-58-004 | BLOCKED | 2025-11-25 | SPRINT_302_docs_tasks_md_ii | Docs Guild · Evidence Locker Guild | docs/modules/airgap | Document `/docs/airgap/portable-evidence.md` for exporting/importing portable evidence bundles across enclaves. Dependencies: DOCS-AIRGAP-58-003. | Blocked: DOCS-AIRGAP-58-003 outstanding; needs Evidence Locker attestation notes (002_ATEL0101) | DOAG0101 | | DOCS-AIRGAP-DEVPORT-64-001 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · DevPortal Offline Guild | docs/modules/export-center/devportal-offline.md | Create `/docs/airgap/devportal-offline.md` describing offline bundle usage and verification. | Requires #3 draft | DEVL0102 | | DOCS-ATTEST-73-001 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Service Guild (docs) | | Publish `/docs/modules/attestor/overview.md` with imposed rule banner. | — | DOAT0101 | -| DOCS-ATTEST-73-002 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestation Payloads Guild (docs) | | Write `/docs/modules/attestor/payloads.md` with schemas/examples. Dependencies: DOCS-ATTEST-73-001. | — | DOAT0101 | -| DOCS-ATTEST-73-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Policy Guild (docs) | | Publish `/docs/modules/attestor/policies.md` covering verification policies. Dependencies: DOCS-ATTEST-73-002. | — | DOAT0101 | -| DOCS-ATTEST-73-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Service Guild (docs) | | Add `/docs/modules/attestor/workflows.md` detailing ingest, verify, bulk operations. Dependencies: DOCS-ATTEST-73-003. | — | DOAT0101 | -| DOCS-ATTEST-74-001 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, KMS Guild (docs) | | Publish `/docs/modules/attestor/keys-and-issuers.md`. Dependencies: DOCS-ATTEST-73-004. | — | DOAT0101 | -| DOCS-ATTEST-74-002 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Transparency Guild (docs) | | Document `/docs/modules/attestor/transparency.md` with witness usage/offline validation. Dependencies: DOCS-ATTEST-74-001. | — | DOAT0101 | -| DOCS-ATTEST-74-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Console Guild (docs) | | Write `/docs/console/attestor-ui.md` with screenshots/workflows. Dependencies: DOCS-ATTEST-74-002. | — | DOAT0101 | -| DOCS-ATTEST-74-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, CLI Attestor Guild (docs) | | Publish `/docs/modules/cli/guides/attest.md` covering CLI usage. Dependencies: DOCS-ATTEST-74-003. | — | DOAT0101 | -| DOCS-ATTEST-75-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, Export Attestation Guild (docs) | | Add `/docs/modules/attestor/airgap.md` for attestation bundles. Dependencies: DOCS-ATTEST-74-004. | — | DOAT0101 | -| DOCS-ATTEST-75-002 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, Security Guild (docs) | | Update `/docs/security/aoc-invariants.md` with attestation invariants. Dependencies: DOCS-ATTEST-75-001. | — | DOAT0101 | +| DOCS-ATTEST-73-002 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestation Payloads Guild (docs) | | Write `/docs/modules/attestor/payloads.md` with schemas/examples. Dependencies: DOCS-ATTEST-73-001. | — | DOAT0101 | +| DOCS-ATTEST-73-003 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Policy Guild (docs) | | Publish `/docs/modules/attestor/policies.md` covering verification policies. Dependencies: DOCS-ATTEST-73-002. | — | DOAT0101 | +| DOCS-ATTEST-73-004 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Service Guild (docs) | | Add `/docs/modules/attestor/workflows.md` detailing ingest, verify, bulk operations. Dependencies: DOCS-ATTEST-73-003. | — | DOAT0101 | +| DOCS-ATTEST-74-001 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, KMS Guild (docs) | | Publish `/docs/modules/attestor/keys-and-issuers.md`. Dependencies: DOCS-ATTEST-73-004. | — | DOAT0101 | +| DOCS-ATTEST-74-002 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Transparency Guild (docs) | | Document `/docs/modules/attestor/transparency.md` with witness usage/offline validation. Dependencies: DOCS-ATTEST-74-001. | — | DOAT0101 | +| DOCS-ATTEST-74-003 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Console Guild (docs) | | Write `/docs/console/attestor-ui.md` with screenshots/workflows. Dependencies: DOCS-ATTEST-74-002. | — | DOAT0101 | +| DOCS-ATTEST-74-004 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, CLI Attestor Guild (docs) | | Publish `/docs/modules/cli/guides/attest.md` covering CLI usage. Dependencies: DOCS-ATTEST-74-003. | — | DOAT0101 | +| DOCS-ATTEST-75-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Export Attestation Guild (docs) | | Add `/docs/modules/attestor/airgap.md` for attestation bundles. Dependencies: DOCS-ATTEST-74-004. | — | DOAT0101 | +| DOCS-ATTEST-75-002 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Security Guild (docs) | | Update `/docs/security/aoc-invariants.md` with attestation invariants. Dependencies: DOCS-ATTEST-75-001. | — | DOAT0101 | | DOCS-CLI-41-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, DevEx/CLI Guild (docs) | docs/modules/cli/guides | Publish `/docs/modules/cli/guides/overview.md`, `/docs/modules/cli/guides/configuration.md`, `/docs/modules/cli/guides/output-and-exit-codes.md` with imposed rule statements. | — | DOCL0101 | | DOCS-CLI-42-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild (docs) | docs/modules/cli/guides | Publish `/docs/modules/cli/guides/parity-matrix.md` and command guides under `/docs/modules/cli/guides/commands/*.md` (policy, sbom, vuln, vex, advisory, export, orchestrator, notify, aoc, auth). Dependencies: DOCS-CLI-41-001. | — | DOCL0101 | -| DOCS-CLI-DET-01 | TODO | | SPRINT_301_docs_tasks_md_i | Docs Guild · DevEx/CLI Guild | | Document `stella sbomer` verbs (`layer`, `compose`, `drift`, `verify`) with examples & offline instructions. | CLI-SBOM-60-001; CLI-SBOM-60-002 | DOCL0101 | +| DOCS-CLI-DET-01 | DONE | 2025-11-23 | SPRINT_301_docs_tasks_md_i | Docs Guild · DevEx/CLI Guild | | Document `stella sbomer` verbs (`layer`, `compose`, `drift`, `verify`) with examples & offline instructions. | CLI-SBOM-60-001; CLI-SBOM-60-002 | DOCL0101 | | DOCS-CLI-FORENSICS-53-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, DevEx/CLI Guild (docs) | docs/modules/cli/guides | Publish `/docs/modules/cli/guides/forensics.md` for snapshot/verify/attest commands with sample outputs, imposed rule banner, and offline workflows. | — | DOCL0101 | | DOCS-CLI-OBS-52-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, DevEx/CLI Guild (docs) | docs/modules/cli/guides | Create `/docs/modules/cli/guides/observability.md` detailing `stella obs` commands, examples, exit codes, imposed rule banner, and scripting tips. | — | DOCL0101 | -| DOCS-CONSOLE-OBS-52-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, Console Guild (docs) | | Document `/docs/console/observability.md` showcasing Observability Hub widgets, trace/log search, imposed rule banner, and accessibility tips. | — | DOCL0101 | -| DOCS-CONSOLE-OBS-52-002 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, Console Guild (docs) | | Publish `/docs/console/forensics.md` covering timeline explorer, evidence viewer, attestation verifier, imposed rule banner, and troubleshooting. Dependencies: DOCS-CONSOLE-OBS-52-001. | — | DOCL0101 | -| DOCS-CONTRIB-62-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, API Governance Guild (docs) | | Publish `/docs/contributing/api-contracts.md` detailing how to edit OAS, lint rules, compatibility checks. | — | DOCL0101 | +| DOCS-CONSOLE-OBS-52-001 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Console Guild (docs) | | Document `/docs/console/observability.md` showcasing Observability Hub widgets, trace/log search, imposed rule banner, and accessibility tips. | Blocked: awaiting Console Observability Hub schemas/widgets from Console Guild | DOCL0101 | +| DOCS-CONSOLE-OBS-52-002 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Console Guild (docs) | | Publish `/docs/console/forensics.md` covering timeline explorer, evidence viewer, attestation verifier, imposed rule banner, and troubleshooting. Dependencies: DOCS-CONSOLE-OBS-52-001. | Blocked: upstream DOCS-CONSOLE-OBS-52-001 | DOCL0101 | +| DOCS-CONTRIB-62-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, API Governance Guild (docs) | docs/contributing/api-contracts.md | Publish `/docs/contributing/api-contracts.md` detailing how to edit OAS, lint rules, compatibility checks. | — | DOCL0101 | | DOCS-DETER-70-002 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Scanner Guild | docs/modules/scanner/determinism.md | Document the scanner determinism score process (`determinism.json` schema, CI harness, replay instructions) under `/docs/modules/scanner/determinism-score.md` and add a release-notes template entry. Dependencies: SCAN-DETER-186-010, DEVOPS-SCAN-90-004. | Need deterministic suite notes from 137_SCDT0101 | DOSC0101 | | DOCS-DEVPORT-62-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Developer Portal Guild (docs) | docs/devportal/publishing.md | Document `/docs/devportal/publishing.md` for build pipeline, offline bundle steps. | — | DOCL0101 | | DOCS-DSL-401-005 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | Docs Guild (`docs/policy/dsl.md`, `docs/policy/lifecycle.md`) | `docs/policy/dsl.md`, `docs/policy/lifecycle.md` | Refresh `docs/policy/dsl.md` + lifecycle docs with the new syntax, signal dictionary (`trust_score`, `reachability`, etc.), authoring workflow, and safety rails (shadow mode, coverage tests). | — | DOCL0101 | | DOCS-ENTROPY-70-004 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Scanner Guild | docs/modules/scanner/determinism.md | Publish entropy analysis documentation (scoring heuristics, JSON schemas, policy hooks, UI guidance) under `docs/modules/scanner/entropy.md` and update trust-lattice references. Dependencies: SCAN-ENTROPY-186-011/012, POLICY-RISK-90-001. | Requires entropy guardrails from 078_SCSA0301 | DOSC0101 | -| DOCS-EXC-25-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Author `/docs/governance/exceptions.md` covering lifecycle, scope patterns, examples, compliance checklist. | CLEX0101 outputs | DOEX0102 | -| DOCS-EXC-25-002 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Publish `/docs/governance/approvals-and-routing.md` detailing roles, routing matrix, MFA rules, audit trails. Dependencies: DOCS-EXC-25-001. | CLEX0101 | DOEX0102 | -| DOCS-EXC-25-003 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Create `/docs/api/exceptions.md` with endpoints, payloads, errors, idempotency notes. Dependencies: DOCS-EXC-25-002. | UIEX0101 | DOEX0102 | -| DOCS-EXC-25-005 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs + Accessibility Guilds | docs/modules/excititor | Write `/docs/ui/exception-center.md` with UI walkthrough, badges, accessibility, shortcuts. Dependencies: DOCS-EXC-25-003. | UIEX0101 | DOEX0102 | +| DOCS-EXC-25-001 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Author `/docs/governance/exceptions.md` covering lifecycle, scope patterns, examples, compliance checklist. | Blocked: waiting on CLEX0101 exception governance spec and UI workflow | DOEX0102 | +| DOCS-EXC-25-002 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Publish `/docs/governance/approvals-and-routing.md` detailing roles, routing matrix, MFA rules, audit trails. Dependencies: DOCS-EXC-25-001. | Blocked: upstream DOCS-EXC-25-001 | DOEX0102 | +| DOCS-EXC-25-003 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Create `/docs/api/exceptions.md` with endpoints, payloads, errors, idempotency notes. Dependencies: DOCS-EXC-25-002. | Blocked: upstream DOCS-EXC-25-002 | DOEX0102 | +| DOCS-EXC-25-005 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs + Accessibility Guilds | docs/modules/excititor | Write `/docs/ui/exception-center.md` with UI walkthrough, badges, accessibility, shortcuts. Dependencies: DOCS-EXC-25-003. | Blocked: upstream DOCS-EXC-25-003 | DOEX0102 | | DOCS-EXC-25-006 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Update `/docs/modules/cli/guides/exceptions.md` covering command usage and exit codes. Dependencies: DOCS-EXC-25-005. | CLEX0101 | DOEX0102 | | DOCS-EXC-25-007 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · DevOps Guild | docs/modules/excititor | Publish `/docs/migration/exception-governance.md` describing cutover from legacy suppressions, notifications, rollback. Dependencies: DOCS-EXC-25-006. | UIEX0101 & Ops runbooks | DOEX0102 | | DOCS-EXPORT-37-004 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Export Center Guild | docs/modules/export-center | Publish `/docs/security/export-hardening.md` outlining RBAC, tenancy, encryption, redaction, restating imposed rule. | Wait for ATMI0102 orchestration notes | DOEC0102 | @@ -700,21 +700,21 @@ | DOCS-GRAPH-24-005 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · DevEx/CLI Guild | docs/modules/graph | Update `/docs/modules/cli/guides/graph-and-vuln.md` covering new CLI commands, exit codes, scripting. Dependencies: DOCS-GRAPH-24-004. | Wait for CLI samples from CLCI0109 | DOGR0101 | | DOCS-GRAPH-24-006 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Policy Guild | docs/modules/graph | Write `/docs/policy/ui-integration.md` explaining overlays, cache usage, simulator contracts. Dependencies: DOCS-GRAPH-24-005. | Needs policy outputs from PLVL0102 | DOGR0101 | | DOCS-GRAPH-24-007 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · DevOps Guild | docs/modules/graph | Produce `/docs/migration/graph-parity.md` with rollout plan, parity checks, fallback guidance. Dependencies: DOCS-GRAPH-24-006. | Depends on DVDO0108 deployment notes | DOGR0101 | -| DOCS-INSTALL-44-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/overview.md` and `/docs/install/compose-quickstart.md` with imposed rule line and copy-ready commands. | Need DVPL0101 compose schema | DOIS0101 | -| DOCS-INSTALL-45-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/helm-prod.md` and `/docs/install/configuration-reference.md` with values tables and imposed rule reminder. Dependencies: DOCS-INSTALL-44-001. | Wait for updated TLS guidance from 127_SIGR0101 | DOIS0101 | -| DOCS-INSTALL-46-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/airgap.md`, `/docs/security/supply-chain.md`, `/docs/operations/health-and-readiness.md`, `/docs/release/image-catalog.md`, `/docs/console/onboarding.md` (each with imposed rule). Dependencies: DOCS-INSTALL-45-001. | Depends on 126_RLRC0101 replay hooks | DOIS0101 | -| DOCS-INSTALL-50-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · DevOps Guild | docs/install | Add `/docs/install/telemetry-stack.md` with collector deployment, exporter options, offline kit notes, and imposed rule banner. Dependencies: DOCS-INSTALL-46-001. | Requires DevOps offline validation (DVDO0107) | DOIS0101 | +| DOCS-INSTALL-44-001 | BLOCKED | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/overview.md` and `/docs/install/compose-quickstart.md` with imposed rule line and copy-ready commands. | Blocked: waiting on DVPL0101 compose schema + service list/version pins | DOIS0101 | +| DOCS-INSTALL-45-001 | BLOCKED | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/helm-prod.md` and `/docs/install/configuration-reference.md` with values tables and imposed rule reminder. Dependencies: DOCS-INSTALL-44-001. | Blocked: upstream DOCS-INSTALL-44-001 and TLS guidance (127_SIGR0101) | DOIS0101 | +| DOCS-INSTALL-46-001 | BLOCKED | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/airgap.md`, `/docs/security/supply-chain.md`, `/docs/operations/health-and-readiness.md`, `/docs/release/image-catalog.md`, `/docs/console/onboarding.md` (each with imposed rule). Dependencies: DOCS-INSTALL-45-001. | Blocked: upstream DOCS-INSTALL-45-001 and 126_RLRC0101 replay hooks | DOIS0101 | +| DOCS-INSTALL-50-001 | BLOCKED | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · DevOps Guild | docs/install | Add `/docs/install/telemetry-stack.md` with collector deployment, exporter options, offline kit notes, and imposed rule banner. Dependencies: DOCS-INSTALL-46-001. | Blocked: upstream DOCS-INSTALL-46-001; awaiting DevOps offline validation (DVDO0107) | DOIS0101 | | DOCS-LNM-22-001 | BLOCKED | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs Guild · Concelier Guild | docs/modules/concelier/link-not-merge.md | Author `/docs/advisories/aggregation.md` covering observation vs linkset, conflict handling, AOC requirements, and reviewer checklist. | Need final schema text from 005_ATLN0101 | DOLN0101 | | DOCS-LNM-22-002 | BLOCKED | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs Guild · Excititor Guild | docs/modules/concelier/link-not-merge.md | Publish `/docs/vex/aggregation.md` describing VEX observation/linkset model, product matching, conflicts. Dependencies: DOCS-LNM-22-001. | Waiting on Excititor overlay notes | DOLN0101 | | DOCS-LNM-22-003 | BLOCKED | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs Guild · BE-Base Guild | docs/modules/concelier/link-not-merge.md | Update `/docs/api/advisories.md` and `/docs/api/vex.md` for new endpoints, parameters, errors, exports. Dependencies: DOCS-LNM-22-002. | Replay hook contract from RBBN0101 | DOLN0101 | -| DOCS-LNM-22-004 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Policy Guild | docs/modules/concelier/link-not-merge.md | Create `/docs/policy/effective-severity.md` detailing severity selection strategies from multiple sources. Dependencies: DOCS-LNM-22-003. | Requires policy binding from PLVL0102 | DOLN0101 | +| DOCS-LNM-22-004 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Policy Guild | docs/modules/concelier/link-not-merge.md | Create `/docs/policy/effective-severity.md` detailing severity selection strategies from multiple sources. Dependencies: DOCS-LNM-22-003. | Requires policy binding from PLVL0102 | DOLN0101 | | DOCS-LNM-22-005 | BLOCKED | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs Guild · UI Guild | docs/modules/concelier/link-not-merge.md | Document `/docs/ui/evidence-panel.md` with screenshots, conflict badges, accessibility guidance. Dependencies: DOCS-LNM-22-004. | UI signals from 124_CCSL0101 | DOLN0101 | -| DOCS-LNM-22-007 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Observability Guild | docs/modules/concelier/link-not-merge.md | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. Dependencies: DOCS-LNM-22-005. | Observability wiring from 066_PLOB0101 | DOLN0101 | +| DOCS-LNM-22-007 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Observability Guild | docs/modules/concelier/link-not-merge.md | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. Dependencies: DOCS-LNM-22-005. | Observability wiring from 066_PLOB0101 | DOLN0101 | | DOCS-LNM-22-008 | DONE (2025-11-03) | 2025-11-03 | SPRINT_117_concelier_vi | Docs Guild · DevOps Guild | docs/modules/concelier/link-not-merge.md | Documented Link-Not-Merge migration plan in `docs/migration/no-merge.md`; keep synced with ongoing tasks. | Needs retrospective summary | DOLN0101 | -| DOCS-NOTIFY-40-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Security Guild | docs/modules/notify | Publish `/docs/notifications/channels.md`, `/docs/notifications/escalations.md`, `/docs/notifications/api.md`, `/docs/operations/notifier-runbook.md`, `/docs/security/notifications-hardening.md`; each ends with imposed rule line. | Need tenancy + throttling updates from DVDO0110 | DONO0101 | -| DOCS-OAS-61-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · API Contracts Guild | docs/api/oas | Publish `/docs/api/overview.md` covering auth, tenancy, pagination, idempotency, rate limits with banner. | Need governance decisions from 049_APIG0101 | DOOA0101 | -| DOCS-OAS-61-002 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · API Governance Guild | docs/api/oas | Author `/docs/api/conventions.md` capturing naming, errors, filters, sorting, examples. Dependencies: DOCS-OAS-61-001. | Requires review board inputs (APIG0101) | DOOA0101 | -| DOCS-OAS-61-003 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · API Governance Guild | docs/api/oas | Publish `/docs/api/versioning.md` describing SemVer, deprecation headers, migration playbooks. Dependencies: DOCS-OAS-61-002. | Waiting on lint/tooling export from DVDO0108 | DOOA0101 | +| DOCS-NOTIFY-40-001 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Security Guild | docs/modules/notify | Publish `/docs/notifications/channels.md`, `/docs/notifications/escalations.md`, `/docs/notifications/api.md`, `/docs/operations/notifier-runbook.md`, `/docs/security/notifications-hardening.md`; each ends with imposed rule line. | Need tenancy + throttling updates from DVDO0110 | DONO0101 | +| DOCS-OAS-61-001 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · API Contracts Guild | docs/api/overview.md | Publish `/docs/api/overview.md` covering auth, tenancy, pagination, idempotency, rate limits with banner. | Need governance decisions from 049_APIG0101 | DOOA0101 | +| DOCS-OAS-61-002 | BLOCKED | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · API Governance Guild | docs/api/oas | Author `/docs/api/conventions.md` capturing naming, errors, filters, sorting, examples. Dependencies: DOCS-OAS-61-001. | Blocked: awaiting governance inputs (APIG0101) and example approvals | DOOA0101 | +| DOCS-OAS-61-003 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · API Governance Guild | docs/api/oas | Publish `/docs/api/versioning.md` describing SemVer, deprecation headers, migration playbooks. Dependencies: DOCS-OAS-61-002. | Waiting on lint/tooling export from DVDO0108 | DOOA0101 | | DOCS-OAS-62-001 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · DevPortal Guild | docs/api/oas | Stand up `/docs/api/reference/` auto-generated site; integrate with portal nav. Dependencies: DOCS-OAS-61-003. | Needs DevPortal publishing hooks (050_DEVL0101) | DOOA0101 | | DOCS-OBS-50-002 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · Security Guild | docs/observability | Author `/docs/observability/telemetry-standards.md` detailing common fields, scrubbing policy, sampling defaults, and redaction override procedure. | Need console metric list from 059_CNOB0101 | DOOB0101 | | DOCS-OBS-50-003 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · Observability Guild | docs/observability | Create `/docs/observability/logging.md` covering structured log schema, dos/don'ts, tenant isolation, and copyable examples. Dependencies: DOCS-OBS-50-002. | Waiting on observability ADR from 066_PLOB0101 | DOOB0101 | @@ -892,13 +892,13 @@ | ENGINE-50-007 | TODO | | SPRINT_126_policy_reasoning | Policy + Scheduler Worker Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | POLICY-ENGINE-50-006 | POLICY-ENGINE-50-006 | DOPE0105 | | ENGINE-60-001 | TODO | | SPRINT_126_policy_reasoning | Policy + SBOM Service Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | POLICY-ENGINE-50-007 | POLICY-ENGINE-50-007 | DOPE0105 | | ENGINE-60-002 | TODO | | SPRINT_126_policy_reasoning | Policy + BE-Base Platform Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | POLICY-ENGINE-60-001 | POLICY-ENGINE-60-001 | DOPE0105 | -| ENGINE-66-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Baseline collections + indexes doc. | — | DORG0101 | -| ENGINE-66-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-66-001 | RISK-ENGINE-66-001 | DORG0101 | +| ENGINE-66-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Baseline collections + indexes doc. | — | DORG0101 | +| ENGINE-66-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-66-001 | RISK-ENGINE-66-001 | DORG0101 | | ENGINE-67-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + Concelier Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-66-002 | RISK-ENGINE-66-002 | DORG0101 | -| ENGINE-67-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Excititor Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-001 | RISK-ENGINE-67-001 | DORG0101 | -| ENGINE-67-003 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Policy Engine Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-002 | RISK-ENGINE-67-002 | DORG0101 | +| ENGINE-67-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + Excititor Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-001 | RISK-ENGINE-67-001 | DORG0101 | +| ENGINE-67-003 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + Policy Engine Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-002 | RISK-ENGINE-67-002 | DORG0101 | | ENGINE-68-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + Findings Ledger Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-003 | RISK-ENGINE-67-003 | DORG0101 | -| ENGINE-68-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + API Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-68-001 | RISK-ENGINE-68-001 | DORG0101 | +| ENGINE-68-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + API Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-68-001 | RISK-ENGINE-68-001 | DORG0101 | | ENGINE-69-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Policy Studio Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-68-002 | RISK-ENGINE-68-002 | DORG0101 | | ENGINE-69-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Observability Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-69-001 | RISK-ENGINE-69-001 | DORG0101 | | ENGINE-70-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Export Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-69-002 | RISK-ENGINE-69-002 | DORG0101 | @@ -944,9 +944,9 @@ | EXCITITOR-CONN-SUSE-01-003 | TODO | | SPRINT_120_excititor_ii | Excititor Guild (SUSE connector) | src/Excititor/__Libraries/StellaOps.Excititor.Connectors.SUSE.RancherVEXHub | DONE (2025-11-09) – Emit provider trust configuration (signer fingerprints, trust tier notes) into the raw provenance envelope so downstream VEX Lens/Policy components can weigh issuers. Connector must not apply weighting or consensus inside ingestion. | EXCITITOR-CONN-SUSE-01-002; EXCITITOR-POLICY-01-001 | EXCN0101 | | EXCITITOR-CONN-TRUST-01-001 | DONE | 2025-11-20 | SPRINT_0119_0001_0001_excititor_i | Excititor Guild · AirGap Guilds | src/Excititor/__Libraries/StellaOps.Excititor.Connectors* | Signer metadata loader/enricher wired for MSRC/Oracle/Ubuntu/OpenVEX connectors; env `STELLAOPS_CONNECTOR_SIGNER_METADATA_PATH`; docs + sample hash shipped. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXCN0101 | | EXCITITOR-CONN-UBUNTU-01-003 | TODO | | SPRINT_120_excititor_ii | Excititor Guild (Ubuntu connector) | src/Excititor/__Libraries/StellaOps.Excititor.Connectors.Ubuntu.CSAF | DONE (2025-11-09) – Emit Ubuntu signing metadata (GPG fingerprints, issuer trust tier) inside raw provenance artifacts so downstream Policy/VEX Lens consumers can weigh issuers. Connector must remain aggregation-only with no inline weighting. | EXCITITOR-CONN-UBUNTU-01-002 | EXCN0101 | -| EXCITITOR-CONSOLE-23-001 | TODO | | SPRINT_120_excititor_ii | Excititor Guild · Docs Guild | src/Excititor/StellaOps.Excititor.WebService | Expose `/console/vex` endpoints returning grouped VEX statements per advisory/component with status chips, justification metadata, precedence trace pointers, and tenant-scoped filters for Console explorer. Dependencies: EXCITITOR-LNM-21-201, EXCITITOR-LNM-21-202. | DOCN0101 | EXCO0101 | -| EXCITITOR-CONSOLE-23-002 | TODO | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Provide aggregated counts for VEX overrides (new, not_affected, revoked) powering Console dashboard + live status ticker; emit metrics for policy explain integration. Dependencies: EXCITITOR-CONSOLE-23-001, EXCITITOR-LNM-21-203. | EXCITITOR-CONSOLE-23-001 | EXCO0101 | -| EXCITITOR-CONSOLE-23-003 | TODO | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Deliver rapid lookup endpoints of VEX by advisory/component for Console global search; ensure response includes provenance and precedence context; include caching and RBAC. Dependencies: EXCITITOR-CONSOLE-23-001. | EXCITITOR-CONSOLE-23-001 | EXCO0101 | +| EXCITITOR-CONSOLE-23-001 | DONE (2025-11-23) | | SPRINT_120_excititor_ii | Excititor Guild · Docs Guild | src/Excititor/StellaOps.Excititor.WebService | Expose `/console/vex` endpoints returning grouped VEX statements per advisory/component with status chips, justification metadata, precedence trace pointers, and tenant-scoped filters for Console explorer. Dependencies: EXCITITOR-LNM-21-201, EXCITITOR-LNM-21-202. | DOCN0101 | EXCO0101 | +| EXCITITOR-CONSOLE-23-002 | DONE (2025-11-23) | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Provide aggregated counts for VEX overrides (new, not_affected, revoked) powering Console dashboard + live status ticker; emit metrics for policy explain integration. Dependencies: EXCITITOR-CONSOLE-23-001, EXCITITOR-LNM-21-203. | EXCITITOR-CONSOLE-23-001 | EXCO0101 | +| EXCITITOR-CONSOLE-23-003 | DONE (2025-11-23) | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Deliver rapid lookup endpoints of VEX by advisory/component for Console global search; ensure response includes provenance and precedence context; include caching and RBAC. Dependencies: EXCITITOR-CONSOLE-23-001. | EXCITITOR-CONSOLE-23-001 | EXCO0101 | | EXCITITOR-CORE-AOC-19-002 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Implement deterministic extraction of advisory IDs, component PURLs, and references into `linkset`, capturing reconciled-from metadata for traceability. | Link-Not-Merge schema | EXCA0101 | | EXCITITOR-CORE-AOC-19-003 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Enforce `(vendor, upstreamId, contentHash, tenant)` uniqueness, generate supersedes chains, and ensure append-only versioning of raw VEX documents. Dependencies: EXCITITOR-CORE-AOC-19-002. | EXCITITOR-CORE-AOC-19-002 | EXCA0101 | | EXCITITOR-CORE-AOC-19-004 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Excise consensus/merge/severity logic from Excititor ingestion paths, updating exports/tests to rely on Policy Engine materializations instead. Dependencies: EXCITITOR-CORE-AOC-19-003. | EXCITITOR-CORE-AOC-19-003 | EXCA0101 | @@ -957,16 +957,16 @@ | EXCITITOR-GRAPH-21-001 | TODO | 2025-10-27 | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Provide batched VEX/advisory reference fetches keyed by graph node PURLs so UI inspector can display raw documents and justification metadata. | Link-Not-Merge schema | EXGR0101 | | EXCITITOR-GRAPH-21-002 | TODO | 2025-10-27 | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Ensure overlay metadata includes VEX justification summaries and document versions for Cartographer overlays; update fixtures/tests. Dependencies: EXCITITOR-GRAPH-21-001. | EXCITITOR-GRAPH-21-001 | EXGR0101 | | EXCITITOR-GRAPH-21-005 | TODO | 2025-10-27 | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | Add indexes/materialized views for VEX lookups by PURL/policy to support Cartographer inspector performance; document migrations. Dependencies: EXCITITOR-GRAPH-21-002. | EXCITITOR-GRAPH-21-002 | EXGR0101 | -| EXCITITOR-GRAPH-24-101 | TODO | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Provide endpoints delivering VEX status summaries per component/asset for Vuln Explorer integration. Dependencies: EXCITITOR-GRAPH-21-005. | EXCITITOR-GRAPH-21-002 | EXGR0101 | -| EXCITITOR-GRAPH-24-102 | TODO | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Add batch VEX observation retrieval optimized for Graph overlays/tooltips. Dependencies: EXCITITOR-GRAPH-24-101. | EXCITITOR-GRAPH-24-101 | EXGR0101 | +| EXCITITOR-GRAPH-24-101 | DONE (2025-11-25) | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Provide endpoints delivering VEX status summaries per component/asset for Vuln Explorer integration. Dependencies: EXCITITOR-GRAPH-21-005. | EXCITITOR-GRAPH-21-002 | EXGR0101 | +| EXCITITOR-GRAPH-24-102 | DONE (2025-11-25) | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Add batch VEX observation retrieval optimized for Graph overlays/tooltips. Dependencies: EXCITITOR-GRAPH-24-101. | EXCITITOR-GRAPH-24-101 | EXGR0101 | | EXCITITOR-LNM-21-001 | TODO | | SPRINT_121_excititor_iii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | Stand up `vex_observations` and `vex_linksets` collections with shard keys, tenant guards, and migrations that retire any residual merge-era data without mutating raw content. | Link-Not-Merge schema | EXLN0101 | | EXCITITOR-LNM-21-002 | TODO | | SPRINT_121_excititor_iii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Capture disagreement metadata (status + justification deltas) directly inside linksets with confidence scores so downstream consumers can highlight conflicts without Excititor choosing winners. Depends on EXCITITOR-LNM-21-001. | EXCITITOR-LNM-21-001 | EXLN0101 | | EXCITITOR-LNM-21-003 | TODO | | SPRINT_121_excititor_iii | Excititor Core + Platform Events Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Emit `vex.linkset.updated` events and describe payload shape (observation ids, confidence, conflict summary) so Policy/Lens/UI can subscribe while Excititor stays aggregation-only. Depends on EXCITITOR-LNM-21-002. | EXCITITOR-LNM-21-002 | EXLN0101 | -| EXCITITOR-LNM-21-201 | TODO | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Ship `/vex/observations` read endpoints with filters for advisory/product/issuer, strict RBAC, and deterministic pagination (no derived verdict fields). Depends on EXCITITOR-LNM-21-003. | EXCITITOR-LNM-21-001 | EXLN0101 | -| EXCITITOR-LNM-21-202 | TODO | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Provide `/vex/linksets` + export endpoints that surface alias mappings, conflict markers, and provenance proofs exactly as stored; errors must map to `ERR_AGG_*`. Depends on EXCITITOR-LNM-21-201. | EXCITITOR-LNM-21-201 | EXLN0101 | -| EXCITITOR-LNM-21-203 | TODO | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Update OpenAPI, SDK smoke tests, and documentation to cover the new observation/linkset endpoints with realistic examples Advisory AI/Lens teams can rely on. Depends on EXCITITOR-LNM-21-202. | EXCITITOR-LNM-21-202 | EXLN0101 | -| EXCITITOR-OBS-51-001 | TODO | | SPRINT_121_excititor_iii | Excititor Core Guild · DevOps Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Publish ingest latency, scope resolution success, conflict rate, and signature verification metrics plus SLO burn alerts so we can prove Excititor meets the AOC “evidence freshness” mission. | Wait for 046_TLTY0101 span schema | EXOB0101 | -| EXCITITOR-OBS-52-001 | TODO | | SPRINT_122_excititor_iv | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Emit `timeline_event` entries for every ingest/linkset change with trace IDs, justification summaries, and evidence hashes so downstream systems can replay the raw facts chronologically. Depends on EXCITITOR-OBS-51-001. | Needs #1 merged for correlation IDs | EXOB0101 | +| EXCITITOR-LNM-21-201 | DONE (2025-11-25) | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Ship `/vex/observations` read endpoints with filters for advisory/product/issuer, strict RBAC, and deterministic pagination (no derived verdict fields). Depends on EXCITITOR-LNM-21-003. | EXCITITOR-LNM-21-001 | EXLN0101 | +| EXCITITOR-LNM-21-202 | DONE (2025-11-25) | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Provide `/vex/linksets` + export endpoints that surface alias mappings, conflict markers, and provenance proofs exactly as stored; errors must map to `ERR_AGG_*`. Depends on EXCITITOR-LNM-21-201. | EXCITITOR-LNM-21-201 | EXLN0101 | +| EXCITITOR-LNM-21-203 | DONE (2025-11-23) | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Update OpenAPI, SDK smoke tests, and documentation to cover the new observation/linkset endpoints with realistic examples Advisory AI/Lens teams can rely on. Depends on EXCITITOR-LNM-21-202. | EXCITITOR-LNM-21-202 | EXLN0101 | +| EXCITITOR-OBS-51-001 | DONE (2025-11-23) | | SPRINT_121_excititor_iii | Excititor Core Guild · DevOps Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Publish ingest latency, scope resolution success, conflict rate, and signature verification metrics plus SLO burn alerts so we can prove Excititor meets the AOC “evidence freshness” mission. | Wait for 046_TLTY0101 span schema | EXOB0101 | +| EXCITITOR-OBS-52-001 | DONE (2025-11-24) | | SPRINT_0119_0001_0006_excititor_vi | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Emit `timeline_event` entries for every ingest/linkset change with trace IDs, justification summaries, and evidence hashes so downstream systems can replay the raw facts chronologically. Depends on EXCITITOR-OBS-51-001. | Needs #1 merged for correlation IDs | EXOB0101 | | EXCITITOR-OBS-53-001 | TODO | | SPRINT_122_excititor_iv | Excititor Core Guild · Evidence Locker Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Build locker payloads (raw doc, normalization diff, provenance) and Merkle manifests so sealed-mode sites can audit evidence without Excititor reinterpreting it. Depends on EXCITITOR-OBS-52-001. | Blocked on Evidence Locker DSSE hooks (002_ATEL0101) | EXOB0101 | | EXCITITOR-OBS-54-001 | TODO | | SPRINT_122_excititor_iv | Excititor Core Guild · Provenance Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Attach DSSE attestations to every evidence batch, verify chains via Provenance tooling, and surface attestation IDs on timeline events. Depends on EXCITITOR-OBS-53-001. | Requires provenance schema from 005_ATLN0101 | EXOB0101 | | EXCITITOR-OPS-0001 | TODO | | SPRINT_333_docs_modules_excititor | Ops Guild · Docs Guild | docs/modules/excititor | Sync outcomes back to ../.. | DOEX0101 runbooks | DOEX0102 | @@ -975,12 +975,12 @@ | EXCITITOR-POLICY-20-001 | TODO | | SPRINT_122_excititor_iv | WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Provide VEX lookup APIs (PURL/advisory batching, scope filters, tenant enforcement) that Policy Engine uses to join evidence without Excititor performing any verdict logic. Depends on EXCITITOR-AOC-20-004. | DOLN0101 | EXWS0101 | | EXCITITOR-POLICY-20-002 | TODO | | SPRINT_122_excititor_iv | Excititor Core Guild (src/Excititor/__Libraries/StellaOps.Excititor.Core) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Enhance linksets with scope resolution + version range metadata so Policy/Reachability can reason about applicability while Excititor continues to report only raw context. Depends on EXCITITOR-POLICY-20-001. | | EXWK0101 | | EXCITITOR-RISK-66-001 | TODO | | SPRINT_122_excititor_iv | Excititor Core Guild · Risk Engine Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Core`) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Publish risk-engine ready feeds (status, justification, provenance) with zero derived severity so gating services can reference Excititor as a source of truth. Depends on EXCITITOR-POLICY-20-002. | CONCELIER-GRAPH-21-001/002 | EXRS0101 | -| EXCITITOR-STORE-AOC-19-001 | TODO | | SPRINT_123_excititor_v | Storage Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo`) | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | Ship Mongo JSON Schema + validator tooling (including Offline Kit instructions) so operators can prove Excititor stores only immutable evidence. | Link-Not-Merge schema | EXSM0101 | -| EXCITITOR-STORE-AOC-19-002 | TODO | | SPRINT_123_excititor_v | Storage + DevOps Guilds (`src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo`) | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | Create unique indexes, run migrations/backfills, and document rollback steps for the new schema validator. Depends on EXCITITOR-STORE-AOC-19-001. | STORE-AOC-19-001 | EXSM0101 | -| EXCITITOR-VEXLENS-30-001 | TODO | | SPRINT_123_excititor_v | Excititor WebService Guild · VEX Lens Guild | src/Excititor/StellaOps.Excititor.WebService | Ensure every observation exported to VEX Lens carries issuer hints, signature blobs, product tree snippets, and staleness metadata so the lens can compute consensus without calling back into Excititor. | — | PLVL0103 | -| EXCITITOR-VULN-29-001 | TODO | | SPRINT_123_excititor_v | Excititor WebService Guild (`src/Excititor/StellaOps.Excititor.WebService`) | src/Excititor/StellaOps.Excititor.WebService | Canonicalize advisory/product keys (map to `advisory_key`, capture scope metadata) while preserving original identifiers in `links[]`; run backfill + regression tests. | EXWS0101 | EXVN0101 | -| EXCITITOR-VULN-29-002 | TODO | | SPRINT_123_excititor_v | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Provide `/vuln/evidence/vex/{advisory_key}` returning tenant-scoped raw statements, provenance, and attestation references for Vuln Explorer evidence tabs. Depends on EXCITITOR-VULN-29-001. | EXCITITOR-VULN-29-001 | EXVN0101 | -| EXCITITOR-VULN-29-004 | TODO | | SPRINT_123_excititor_v | Excititor WebService + Observability Guilds | src/Excititor/StellaOps.Excititor.WebService | Add metrics/logs for normalization errors, suppression scopes, withdrawn statements, and feed them to Vuln Explorer + Advisory AI dashboards. Depends on EXCITITOR-VULN-29-002. | EXCITITOR-VULN-29-001 | EXVN0101 | +| EXCITITOR-STORE-AOC-19-001 | DONE (2025-11-25) | | SPRINT_0119_0001_0005_excititor_v | Storage Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo`) | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | Ship Mongo JSON Schema + validator tooling (including Offline Kit instructions) so operators can prove Excititor stores only immutable evidence. | Link-Not-Merge schema | EXSM0101 | +| EXCITITOR-STORE-AOC-19-002 | DONE (2025-11-25) | | SPRINT_0119_0001_0005_excititor_v | Storage + DevOps Guilds (`src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo`) | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | Create unique indexes, run migrations/backfills, and document rollback steps for the new schema validator. Depends on EXCITITOR-STORE-AOC-19-001. | EXCITITOR-STORE-AOC-19-001 | EXSM0101 | +| EXCITITOR-VEXLENS-30-001 | BLOCKED (2025-11-25) | Await VEX Lens field list / examples | SPRINT_0119_0001_0005_excititor_v | Excititor WebService Guild · VEX Lens Guild | src/Excititor/StellaOps.Excititor.WebService | Ensure every observation exported to VEX Lens carries issuer hints, signature blobs, product tree snippets, and staleness metadata so the lens can compute consensus without calling back into Excititor. | — | PLVL0103 | +| EXCITITOR-VULN-29-001 | BLOCKED (2025-11-23) | Waiting on advisory_key canonicalization spec | SPRINT_0119_0001_0005_excititor_v | Excititor WebService Guild (`src/Excititor/StellaOps.Excititor.WebService`) | src/Excititor/StellaOps.Excititor.WebService | Canonicalize advisory/product keys (map to `advisory_key`, capture scope metadata) while preserving original identifiers in `links[]`; run backfill + regression tests. | EXWS0101 | EXVN0101 | +| EXCITITOR-VULN-29-002 | BLOCKED (2025-11-23) | Blocked on EXCITITOR-VULN-29-001 | SPRINT_0119_0001_0005_excititor_v | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Provide `/vuln/evidence/vex/{advisory_key}` returning tenant-scoped raw statements, provenance, and attestation references for Vuln Explorer evidence tabs. Depends on EXCITITOR-VULN-29-001. | EXCITITOR-VULN-29-001 | EXVN0101 | +| EXCITITOR-VULN-29-004 | BLOCKED (2025-11-23) | Blocked on EXCITITOR-VULN-29-002 | SPRINT_0119_0001_0005_excititor_v | Excititor WebService + Observability Guilds | src/Excititor/StellaOps.Excititor.WebService | Add metrics/logs for normalization errors, suppression scopes, withdrawn statements, and feed them to Vuln Explorer + Advisory AI dashboards. Depends on EXCITITOR-VULN-29-002. | EXCITITOR-VULN-29-001 | EXVN0101 | | EXCITITOR-WEB-AIRGAP-58-001 | TODO | | SPRINT_124_excititor_vi | WebService Guild · AirGap Guilds | src/Excititor/StellaOps.Excititor.WebService | Emit timeline events + audit logs for mirror bundle imports (bundle ID, scope, actor) and map sealed-mode violations to actionable remediation guidance. | EXAG0101 | EXWS0101 | | EXCITITOR-WEB-OAS-61-001 | TODO | | SPRINT_124_excititor_vi | WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Implement `/.well-known/openapi` with spec version metadata plus standard error envelopes, then update controller/unit tests accordingly. | DOOR0102 | EXWS0101 | | EXCITITOR-WEB-OAS-62-001 | TODO | | SPRINT_124_excititor_vi | WebService Guild · API Governance | src/Excititor/StellaOps.Excititor.WebService | Publish curated examples for the new evidence/attestation/timeline endpoints, emit deprecation headers for legacy routes, and align SDK docs. Depends on EXCITITOR-WEB-OAS-61-001. | EXCITITOR-WEB-OAS-61-001 | EXWS0101 | @@ -1018,7 +1018,7 @@ | EXPORT-OAS-63 | TODO | | SPRINT_160_export_evidence | Exporter Service Guild · API Governance Guild | | Needs API governance sign-off (049_APIG0101) | Needs API governance sign-off (049_APIG0101) | AGEX0101 | | EXPORT-OAS-63-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild · SDK Guild | src/ExportCenter/StellaOps.ExportCenter | Implement deprecation headers and notifications for legacy export endpoints. Dependencies: EXPORT-OAS-62-001. | Requires #3 schema | AGEX0101 | | EXPORT-OBS-50-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild · Observability Guild | src/ExportCenter/StellaOps.ExportCenter | Adopt telemetry core in exporter service + workers, ensuring spans/logs capture profile id, tenant, artifact counts, distribution type, and trace IDs. | Wait for telemetry schema drop from 046_TLTY0101 | ECOB0101 | -| EXPORT-OBS-51-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | Downstream automation awaiting assembler staffing outcome. | PROGRAM-STAFF-1001 | ECOB0101 | +| EXPORT-OBS-51-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | Downstream automation awaiting assembler staffing outcome. | PROGRAM-STAFF-1001 | ECOB0101 | | EXPORT-OBS-52-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild | src/ExportCenter/StellaOps.ExportCenter | Publish timeline events for export lifecycle (`export.requested`, `export.built`, `export.distributed`, `export.failed`) embedding manifest hashes and evidence refs. Provide dedupe + retry logic. Dependencies: EXPORT-OBS-51-001. | Requires shared middleware from task #1 | ECOB0101 | | EXPORT-OBS-53-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild · Evidence Locker Guild | src/ExportCenter/StellaOps.ExportCenter | Push export manifests + distribution transcripts to evidence locker bundles, ensuring Merkle root alignment and DSSE pre-sign data available. Dependencies: EXPORT-OBS-52-001. | Blocked on Evidence Locker DSSE API (002_ATEL0101) | ECOB0101 | | EXPORT-OBS-54-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild · Provenance Guild | src/ExportCenter/StellaOps.ExportCenter | Produce DSSE attestations for each export artifact and distribution target, expose verification API `/exports/{id}/attestation`, and integrate with CLI verify path. Dependencies: EXPORT-OBS-53-001. | PROGRAM-STAFF-1001; EXPORT-MIRROR-ORCH-1501 | ECOB0101 | @@ -1190,12 +1190,12 @@ | LNM-22-005 | BLOCKED (2025-10-27) | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs + UI Guild | | Docs update for UI flows. | DOCS-LNM-22-004 | IMPT0101 | | LNM-22-007 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Observability Guild | docs/modules/concelier/link-not-merge.md | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. Dependencies: DOCS-LNM-22-005. | DOCS-LNM-22-005 | DOLN0102 | | LNM-22-008 | DONE | 2025-11-03 | SPRINT_117_concelier_vi | Docs Guild · DevOps Guild | docs/modules/concelier/link-not-merge.md | Document Link-Not-Merge migration playbook updates in `docs/migration/no-merge.md`, including rollback guidance. | LNM-22-007 | DOLN0102 | -| MIRROR-CRT-56-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild | | Deterministic assembler has no owner; kickoff rescheduled to 2025-11-15. | PROGRAM-STAFF-1001 | ATMI0101 | -| MIRROR-CRT-56-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator · Security Guilds | | DSSE/TUF metadata follows assembler baseline. | MIRROR-CRT-56-001; MIRROR-DSSE-REV-1501; PROV-OBS-53-001 | ATMI0101 | -| MIRROR-CRT-57-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild · AirGap Time Guild | | OCI/time-anchor workstreams blocked pending assembler + time contract. | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | ATMI0101 | -| MIRROR-CRT-57-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild · AirGap Time Guild | | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | ATMI0101 | -| MIRROR-CRT-58-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild · CLI Guild · Exporter Guild | | CLI + Export automation depends on assembler and DSSE/TUF track. | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | ATMI0101 | -| MIRROR-CRT-58-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild · CLI Guild · Exporter Guild | | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | ATMI0101 | +| MIRROR-CRT-56-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild | | Deterministic assembler has no owner; kickoff rescheduled to 2025-11-15. | PROGRAM-STAFF-1001 | ATMI0101 | +| MIRROR-CRT-56-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator · Security Guilds | | DSSE/TUF metadata follows assembler baseline. | MIRROR-CRT-56-001; MIRROR-DSSE-REV-1501; PROV-OBS-53-001 | ATMI0101 | +| MIRROR-CRT-57-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild · AirGap Time Guild | | OCI/time-anchor workstreams blocked pending assembler + time contract. | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | ATMI0101 | +| MIRROR-CRT-57-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild · AirGap Time Guild | | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | ATMI0101 | +| MIRROR-CRT-58-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild · CLI Guild · Exporter Guild | | CLI + Export automation depends on assembler and DSSE/TUF track. | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | ATMI0101 | +| MIRROR-CRT-58-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild · CLI Guild · Exporter Guild | | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | ATMI0101 | | MTLS-11-002 | DONE | 2025-11-08 | SPRINT_100_identity_signing | Authority Core & Security Guild | src/Authority/StellaOps.Authority | Refresh grants enforce original client cert, tokens persist `x5t#S256` metadata, docs updated. | AUTH-DPOP-11-001 | AUIN0102 | | NATIVE-401-015 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | Scanner Worker Guild | `src/Scanner/__Libraries/StellaOps.Scanner.Symbols.Native`, `src/Scanner/__Libraries/StellaOps.Scanner.CallGraph.Native` | Bootstrap Symbols.Native + CallGraph.Native scaffolding and coverage fixtures. | Needs replay requirements from DORR0101 | SCNA0101 | | NOTIFY-38-001 | TODO | | SPRINT_214_web_iii | BE-Base Platform Guild | src/Web/StellaOps.Web | Route approval/rule APIs through Web gateway with tenant scopes. | Wait for NOTY0103 approval payload schema | NOWB0101 | @@ -1247,13 +1247,13 @@ | OBS-50-002 | DOING | | SPRINT_170_notifications_telemetry | Telemetry Core Guild | src/Telemetry/StellaOps.Telemetry.Core | Roll out Helm/collector bundles plus validation tests and DSSE artefacts for telemetry exporters. | OBS-50-001 | TLTY0102 | | OBS-50-003 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · Observability Guild | docs/observability | Publish `/docs/observability/collector-deploy.md` with telemetry baseline + offline flows. | OBS-50-001 | DOOB0102 | | OBS-50-004 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · Observability Guild | docs/observability | Document scrub policy/SOPs (`/docs/observability/scrub-policy.md`). | OBS-50-003 | DOOB0102 | -| OBS-51-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | ops/devops/telemetry | Build shared SLO bus (queue depth, time-anchor drift) feeding exporter/CLI dashboards. | PROGRAM-STAFF-1001 | OBAG0101 | +| OBS-51-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | ops/devops/telemetry | Build shared SLO bus (queue depth, time-anchor drift) feeding exporter/CLI dashboards. | PROGRAM-STAFF-1001 | OBAG0101 | | OBS-51-002 | TODO | | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild | ops/devops/telemetry | Run shadow-mode evaluators + roll metrics into collectors + alert webhooks. | OBS-51-001 | OBAG0101 | | OBS-52-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Emit ingest latency, queue depth, and AOC violation metrics with burn-rate alerts. | ATLN0101 | CNOB0103 | | OBS-52-002 | TODO | | SPRINT_160_export_evidence | Timeline Indexer Guild | src/Timeline/StellaOps.TimelineIndexer | Configure streaming pipeline (retention/backpressure) for timeline events. | OBS-52-001 | TLIX0101 | | OBS-52-003 | TODO | | SPRINT_160_export_evidence | Timeline Indexer Guild | src/Timeline/StellaOps.TimelineIndexer | Add CI validation + schema enforcement for timeline events. | OBS-52-002 | TLIX0101 | | OBS-52-004 | TODO | | SPRINT_160_export_evidence | Timeline Indexer + Security Guilds | src/Timeline/StellaOps.TimelineIndexer | Harden streaming pipeline with auth/encryption + DSSE proofs. | OBS-52-003 | TLIX0101 | -| OBS-53-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | ops/devops/telemetry | Establish provenance SLO signals + exporter hooks. | PROGRAM-STAFF-1001 | PROB0102 | +| OBS-53-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | ops/devops/telemetry | Establish provenance SLO signals + exporter hooks. | PROGRAM-STAFF-1001 | PROB0102 | | OBS-53-002 | TODO | | SPRINT_0513_0001_0001_provenance | Provenance + Security Guild | src/Provenance/StellaOps.Provenance.Attestation | Add attestation metrics + scrubbed logs referencing DSSE bundles. | OBS-53-001 | PROB0102 | | OBS-53-003 | TODO | | SPRINT_0513_0001_0001_provenance | Provenance Guild | src/Provenance/StellaOps.Provenance.Attestation | Ship dashboards/tests proving attestation observability. | OBS-53-002 | PROB0102 | | OBS-54-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild · Provenance Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Needs shared exporter from 1039_EXPORT-OBS-54-001 | Needs shared exporter from 1039_EXPORT-OBS-54-001 | CNOB0101 | @@ -1547,7 +1547,7 @@ | RISK-ENGINE-67-002 | DONE (2025-11-25) | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Excitor Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Integrate VEX gate provider and ensure gating short-circuits scoring as configured | RISK-ENGINE-67-001 | | | RISK-ENGINE-67-003 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Policy Engine Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Add fix availability, asset criticality, and internet exposure providers with caching + TTL enforcement | RISK-ENGINE-67-002 | | | RISK-ENGINE-68-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Findings Ledger Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Persist scoring results + explanation pointers to Findings Ledger; handle incremental updates via input hash | RISK-ENGINE-67-003 | | -| RISK-ENGINE-68-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, API Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Expose APIs | RISK-ENGINE-68-001 | | +| RISK-ENGINE-68-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, API Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Expose APIs | RISK-ENGINE-68-001 | | | RISK-ENGINE-69-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Policy Studio Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Implement simulation mode producing distributions and top movers without mutating ledger | RISK-ENGINE-68-002 | | | RISK-ENGINE-69-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Observability Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Add telemetry | RISK-ENGINE-69-001 | | | RISK-ENGINE-70-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Export Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Support offline provider bundles with manifest verification and missing-data reporting | RISK-ENGINE-69-002 | | @@ -1853,8 +1853,8 @@ | SPL-23-005 | TODO | | SPRINT_128_policy_reasoning | Policy Guild, DevEx Guild / src/Policy/__Libraries/StellaOps.Policy | src/Policy/__Libraries/StellaOps.Policy | | POLICY-SPL-23-004 | | | SPL-24-001 | TODO | | SPRINT_128_policy_reasoning | Policy Guild, Signals Guild / src/Policy/__Libraries/StellaOps.Policy | src/Policy/__Libraries/StellaOps.Policy | | POLICY-SPL-23-005 | | | STORE-401-016 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | Signals Guild · BE-Base Platform Guild (`src/Signals/StellaOps.Signals`, `src/__Libraries/StellaOps.Replay.Core`) | `src/Signals/StellaOps.Signals`, `src/__Libraries/StellaOps.Replay.Core` | | | | -| STORE-AOC-19-001 | TODO | | SPRINT_123_excititor_v | Excititor Storage Guild (src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo) | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | | | | -| STORE-AOC-19-002 | TODO | | SPRINT_123_excititor_v | Excititor Storage Guild, DevOps Guild (src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo) | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | | | | +| STORE-AOC-19-001 | DONE (2025-11-25) | | SPRINT_0119_0001_0005_excititor_v | Excititor Storage Guild (src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo) | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | | | | +| STORE-AOC-19-002 | DONE (2025-11-25) | | SPRINT_0119_0001_0005_excititor_v | Excititor Storage Guild, DevOps Guild (src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo) | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | | | | | STORE-AOC-19-005 | TODO | 2025-11-04 | SPRINT_115_concelier_iv | Concelier Storage Guild, DevOps Guild (src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo) | src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo | | | | | SURFACE-01 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | | | | | SURFACE-02 | TODO | | SPRINT_136_scanner_surface | Scheduler Worker Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker) | src/Scheduler/__Libraries/StellaOps.Scheduler.Worker | | SURFACE-FS-02; SCHED-SURFACE-01 | | @@ -1963,7 +1963,7 @@ | TEN-49-001 | TODO | | SPRINT_205_cli_v | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | | | | | TEST-186-006 | TODO | | SPRINT_186_record_deterministic_execution | Signing Guild, QA Guild (`src/Signer/StellaOps.Signer.Tests`) | `src/Signer/StellaOps.Signer.Tests` | | | | | TEST-62-001 | TODO | | SPRINT_310_docs_tasks_md_x | Docs Guild, Contract Testing Guild (docs) | | | | | -| TIME-57-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | | PROGRAM-STAFF-1001 | | +| TIME-57-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | | PROGRAM-STAFF-1001 | | | TIME-57-002 | TODO | | SPRINT_510_airgap | Exporter Guild · AirGap Time Guild · CLI Guild | src/AirGap/StellaOps.AirGap.Time | PROGRAM-STAFF-1001 | PROGRAM-STAFF-1001 | AGTM0101 | | TIME-58-001 | TODO | | SPRINT_510_airgap | AirGap Time Guild | src/AirGap/StellaOps.AirGap.Time | AIRGAP-TIME-58-001 | AIRGAP-TIME-58-001 | AGTM0101 | | TIME-58-002 | TODO | | SPRINT_510_airgap | AirGap Time Guild · Notifications Guild | src/AirGap/StellaOps.AirGap.Time | TIME-58-001 | TIME-58-001 | AGTM0101 | @@ -2077,8 +2077,8 @@ | VULN-29-012 | TODO | | SPRINT_311_docs_tasks_md_xi | Docs Guild, Ops Guild (docs) | | | | | | VULN-29-013 | TODO | | SPRINT_311_docs_tasks_md_xi | Docs Guild, Deployment Guild (docs) | | | | | | VULN-API-29-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Define OpenAPI spec (list/detail/query/simulation/workflow/export), query JSON schema, pagination/grouping contracts, and error codes | | PLVA0101 | -| VULN-API-29-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Implement list/query endpoints with policy parameter, grouping, server paging, caching, and cost budgets | VULN-API-29-001 | PLVA0101 | -| VULN-API-29-003 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Implement detail endpoint aggregating evidence, policy rationale, paths | VULN-API-29-002 | PLVA0101 | +| VULN-API-29-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Implement list/query endpoints with policy parameter, grouping, server paging, caching, and cost budgets; tests at `tests/TestResults/vuln-explorer/api.trx`. | VULN-API-29-001 | PLVA0101 | +| VULN-API-29-003 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Implement detail endpoint aggregating evidence, policy rationale, paths | VULN-API-29-002 | PLVA0101 | | VULN-API-29-004 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild, Findings Ledger Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Expose workflow endpoints | VULN-API-29-003 | PLVA0101 | | VULN-API-29-005 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild, Policy Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Implement simulation endpoint comparing `policy_from` vs `policy_to`, returning diffs without side effects; hook into Policy Engine batch eval | VULN-API-29-004 | PLVA0101 | | VULN-API-29-006 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Integrate resolver results with Graph Explorer: include shortest path metadata, line up deep-link parameters, expose `paths` array in details | VULN-API-29-005 | PLVA0101 | @@ -2270,20 +2270,20 @@ | 45-002 | BLOCKED | 2025-11-25 | SPRINT_502_ops_deployment_ii | Deployment Guild · Security Guild (ops/deployment) | ops/deployment | 45-001 | 45-001 | DVDO0103 | | 45-003 | BLOCKED | 2025-11-25 | SPRINT_502_ops_deployment_ii | Deployment Guild · Observability Guild (ops/deployment) | ops/deployment | 45-002 | 45-002 | DVDO0103 | | 50-002 | DOING | | SPRINT_170_notifications_telemetry | Telemetry Core Guild | src/Telemetry/StellaOps.Telemetry.Core | SGSI0101 feed availability | SGSI0101 feed availability | TLTY0101 | -| 51-002 | TODO | | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild · Security Guild | src/Telemetry/StellaOps.Telemetry.Core | OBS-50 baselines | OBS-50 baselines | TLTY0101 | -| 54-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | Await PGMI0101 staffing confirmation | PROGRAM-STAFF-1001 | AGCO0101 | -| 56-001 | TODO | | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild | src/Telemetry/StellaOps.Telemetry.Core | SGSI0101 provenance | SGSI0101 provenance | TLTY0101 | +| 51-002 | BLOCKED | 2025-11-25 | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild · Security Guild | src/Telemetry/StellaOps.Telemetry.Core | OBS-50 baselines | Waiting on OBS-50 baselines and ORCH-OBS-50-001 schemas | TLTY0101 | +| 54-001 | BLOCKED | 2025-11-25 | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | Await PGMI0101 staffing confirmation | Staffing not assigned (PROGRAM-STAFF-1001) | AGCO0101 | +| 56-001 | BLOCKED | 2025-11-25 | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild | src/Telemetry/StellaOps.Telemetry.Core | SGSI0101 provenance | Blocked: SGSI0101 provenance feed/contract pending | TLTY0101 | | 58 series | TODO | | SPRINT_0120_0000_0001_policy_reasoning | Findings Ledger Guild · AirGap Guilds · Evidence Locker Guild | src/Findings/StellaOps.Findings.Ledger | | | PLLG0102 | | 61-001 | TODO | | SPRINT_511_api | API Governance Guild | src/Api/StellaOps.Api.Governance | — | — | APIG0101 | | 61-002 | TODO | | SPRINT_511_api | API Governance Guild | src/Api/StellaOps.Api.Governance | 61-001 | 61-001 | APIG0101 | -| 62-001 | TODO | | SPRINT_206_devportal | DevPortal Guild | src/DevPortal/StellaOps.DevPortal.Site | APIG0101 outputs | APIG0101 outputs | DEVL0101 | -| 62-002 | TODO | | SPRINT_206_devportal | DevPortal Guild | src/DevPortal/StellaOps.DevPortal.Site | 62-001 | 62-001 | DEVL0101 | -| 63-001 | TODO | | SPRINT_206_devportal | DevPortal Guild · Platform Guild | src/DevPortal/StellaOps.DevPortal.Site | 62-002 | 62-002 | DEVL0101 | +| 62-001 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild | src/DevPortal/StellaOps.DevPortal.Site | APIG0101 outputs | Waiting on APIG0101 outputs / API baseline | DEVL0101 | +| 62-002 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild | src/DevPortal/StellaOps.DevPortal.Site | 62-001 | Blocked: 62-001 not delivered | DEVL0101 | +| 63-001 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild · Platform Guild | src/DevPortal/StellaOps.DevPortal.Site | 62-002 | Blocked: 62-002 outstanding | DEVL0101 | | 63-002 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild · SDK Generator Guild | src/DevPortal/StellaOps.DevPortal.Site | 63-001 | Blocked: 63-001 outstanding | DEVL0101 | -| 63-003 | TODO | | SPRINT_0208_0001_0001_sdk | SDK Generator Guild | src/Sdk/StellaOps.Sdk.Generator | APIG0101 outputs | APIG0101 outputs | SDKG0101 | -| 63-004 | TODO | | SPRINT_0208_0001_0001_sdk | SDK Generator Guild | src/Sdk/StellaOps.Sdk.Generator | 63-003 | 63-003 | SDKG0101 | -| 64-001 | TODO | | SPRINT_206_devportal | DevPortal Guild · Export Center Guild | src/DevPortal/StellaOps.DevPortal.Site | Export profile review | Export profile review | DEVL0101 | -| 64-002 | TODO | | SPRINT_160_export_evidence | DevPortal Offline + AirGap Controller Guilds | docs/modules/export-center/devportal-offline.md | Wait for Mirror staffing confirmation (001_PGMI0101) | Wait for Mirror staffing confirmation (001_PGMI0101) | DEVL0102 | +| 63-003 | BLOCKED | 2025-11-25 | SPRINT_0208_0001_0001_sdk | SDK Generator Guild | src/Sdk/StellaOps.Sdk.Generator | APIG0101 outputs | Waiting on APIG0101 outputs | SDKG0101 | +| 63-004 | BLOCKED | 2025-11-25 | SPRINT_0208_0001_0001_sdk | SDK Generator Guild | src/Sdk/StellaOps.Sdk.Generator | 63-003 | Blocked: 63-003 outstanding | SDKG0101 | +| 64-001 | BLOCKED | 2025-11-25 | SPRINT_206_devportal | DevPortal Guild · Export Center Guild | src/DevPortal/StellaOps.DevPortal.Site | Export profile review | Waiting on export profile review doc | DEVL0101 | +| 64-002 | BLOCKED | 2025-11-25 | SPRINT_160_export_evidence | DevPortal Offline + AirGap Controller Guilds | docs/modules/export-center/devportal-offline.md | Wait for Mirror staffing confirmation (001_PGMI0101) | Wait for Mirror staffing confirmation (001_PGMI0101) | DEVL0102 | | 73-001 | DONE | 2025-11-03 | SPRINT_100_identity_signing | KMS Guild | src/__Libraries/StellaOps.Cryptography.Kms | Staffing + DSSE contract (PGMI0101, ATEL0101) | Staffing + DSSE contract (PGMI0101, ATEL0101) | KMSI0101 | | 73-002 | DONE | 2025-11-03 | SPRINT_100_identity_signing | KMS Guild | src/__Libraries/StellaOps.Cryptography.Kms | Depends on #1, FIDO2 profile | FIDO2 | KMSI0101 | | ADVISORY-AI-DOCS-0001 | TODO | | SPRINT_312_docs_modules_advisory_ai | Docs Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | Align with ./AGENTS.md | — | DOAI0101 | @@ -2292,24 +2292,24 @@ | AIAI-31-001 | DONE | 2025-11-09 | SPRINT_110_ingestion_evidence | Excititor Web/Core Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Validate Excititor hand-off replay | Validate Excititor hand-off replay | ADAI0102 | | AIAI-31-002 | DONE | 2025-11-18 | SPRINT_110_ingestion_evidence | Concelier Core · Concelier WebService Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Structured field/caching aligned to LNM schema; awaiting downstream adoption only. | CONCELIER-GRAPH-21-001; CARTO-GRAPH-21-002 | ADAI0102 | | AIAI-31-003 | DONE | 2025-11-12 | SPRINT_110_ingestion_evidence | Concelier Observability Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | Await observability evidence upload | Await observability evidence upload | ADAI0102 | -| AIAI-31-004 | DOING | | SPRINT_110_ingestion_evidence | Docs Guild · Console Guild | | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | DOAI0101 | +| AIAI-31-004 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Docs Guild · Console Guild | | Guardrail console doc published with fixtures and screenshots. | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | DOAI0101 | | AIAI-31-005 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Docs Guild | | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOAI0101 | | AIAI-31-006 | DONE | 2025-11-13 | SPRINT_0111_0001_0001_advisoryai | Docs Guild, Policy Guild (docs) | | — | — | DOAI0101 | | AIAI-31-008 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Advisory AI Guild | | Remote inference packaging delivered with on-prem container + manifests. | AIAI-31-006; AIAI-31-007 | DOAI0101 | | AIAI-31-009 | DONE | 2025-11-12 | SPRINT_110_ingestion_evidence | Advisory AI Guild | | Regression suite + `AdvisoryAI:Guardrails` config landed with perf budgets. | — | DOAI0101 | | AIRGAP-46-001 | TODO | | SPRINT_501_ops_deployment_i | Deployment Guild · Offline Kit Guild | ops/deployment | Needs Mirror staffing + DSSE plan (001_PGMI0101, 002_ATEL0101) | Needs Mirror staffing + DSSE plan (001_PGMI0101, 002_ATEL0101) | AGDP0101 | -| AIRGAP-56 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Needs Link-Not-Merge schema from 005_ATLN0101 | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | -| AIRGAP-56-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | docs/modules/airgap/airgap-mode.md | Dependent on #2 + AirGap Time contract | PROGRAM-STAFF-1001 | AGCO0101 | +| AIRGAP-56 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Air-gap ingest parity delivered against frozen LNM schema. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | +| AIRGAP-56-001 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | docs/modules/airgap/airgap-mode.md | Mirror import helpers and bundle catalog wired for sealed mode. | PROGRAM-STAFF-1001 | AGCO0101 | | AIRGAP-56-001..58-001 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Concelier Core · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Deterministic bundle + manifest/entry-trace and sealed-mode deploy runbook shipped. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ELOCKER-CONTRACT-2001 | AGCO0101 | | AIRGAP-56-002 | DONE | | SPRINT_170_notifications_telemetry | Notifications Service Guild · DevOps Guild | src/Notify/StellaOps.Notify | | | NOTY0101 | | AIRGAP-56-003 | TODO | | SPRINT_301_docs_tasks_md_i | Docs Guild · Exporter Guild | docs/modules/airgap | DOCS-AIRGAP-56-002 | DOCS-AIRGAP-56-002 | AIDG0101 | | AIRGAP-56-004 | TODO | | SPRINT_301_docs_tasks_md_i | Docs Guild · Deployment Guild | docs/modules/airgap | AIRGAP-56-003 | DOCS-AIRGAP-56-003 | AIDG0101 | -| AIRGAP-57 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Needs AirGap staffing (#1) and ATTEST-PLAN-2001 | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | +| AIRGAP-57 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Air-gap bundle timeline/hooks completed. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | | AIRGAP-57-001 | DONE | 2025-11-08 | SPRINT_100_identity_signing | Authority Core & Security Guild, DevOps Guild (src/Authority/StellaOps.Authority) | src/Authority/StellaOps.Authority | | AUTH-AIRGAP-56-001; DEVOPS-AIRGAP-57-002 | KMSI0101 | | AIRGAP-57-002 | DOING | 2025-11-08 | SPRINT_503_ops_devops_i | DevOps Guild, Authority Guild (ops/devops) | ops/devops | | | DVDO0101 | | AIRGAP-57-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · CLI Guild | docs/modules/airgap | CLI & ops inputs | CLI & ops inputs | AIDG0101 | | AIRGAP-57-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · Ops Guild | docs/modules/airgap | AIRGAP-57-003 | AIRGAP-57-003 | AIDG0101 | -| AIRGAP-58 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Depends on Concelier graph schema (005_ATLN0101) | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | +| AIRGAP-58 | DONE (2025-11-24) | 2025-11-24 | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | docs/modules/airgap/airgap-mode.md | Import/export automation delivered for frozen schema. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | AGCO0101 | | AIRGAP-58-001 | TODO | | SPRINT_112_concelier_i | Concelier Core Guild · Evidence Locker Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | | | AGCN0101 | | AIRGAP-58-002 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Security Guild (docs) | docs/modules/airgap | | | AIDG0101 | | AIRGAP-58-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, DevEx Guild (docs) | docs/modules/airgap | | | AIDG0101 | @@ -2326,7 +2326,7 @@ | AIRGAP-IMP-57-002 | TODO | | SPRINT_510_airgap | AirGap Importer Guild · DevOps Guild | src/AirGap/StellaOps.AirGap.Importer | Implement object-store loader storing artifacts under tenant/global mirror paths with Zstandard decompression and checksum validation. Dependencies: AIRGAP-IMP-57-001. | 57-001 | AGIM0101 | | AIRGAP-IMP-58-001 | TODO | | SPRINT_510_airgap | AirGap Importer Guild · CLI Guild | src/AirGap/StellaOps.AirGap.Importer | Implement API (`POST /airgap/import`, `/airgap/verify`) and CLI commands wiring verification + catalog updates, including diff preview. Dependencies: AIRGAP-IMP-57-002. | CLI contract alignment | AGIM0101 | | AIRGAP-IMP-58-002 | TODO | | SPRINT_510_airgap | AirGap Importer Guild · Observability Guild | src/AirGap/StellaOps.AirGap.Importer | Emit timeline events (`airgap.import.started. Dependencies: AIRGAP-IMP-58-001. | 58-001 observability | AGIM0101 | -| AIRGAP-TIME-57-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001; AIRGAP-TIME-CONTRACT-1501 | PROGRAM-STAFF-1001; AIRGAP-TIME-CONTRACT-1501 | ATMI0102 | +| AIRGAP-TIME-57-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001; AIRGAP-TIME-CONTRACT-1501 | PROGRAM-STAFF-1001; AIRGAP-TIME-CONTRACT-1501 | ATMI0102 | | AIRGAP-TIME-57-002 | TODO | | SPRINT_510_airgap | AirGap Time Guild · Observability Guild | src/AirGap/StellaOps.AirGap.Time | Add telemetry counters for time anchors (`airgap_time_anchor_age_seconds`) and alerts for approaching thresholds. Dependencies: AIRGAP-TIME-57-001. | Controller schema | AGTM0101 | | AIRGAP-TIME-58-001 | TODO | | SPRINT_510_airgap | AirGap Time Guild | src/AirGap/StellaOps.AirGap.Time | Persist drift baseline, compute per-content staleness (advisories, VEX, policy) based on bundle metadata, and surface through controller status API. Dependencies: AIRGAP-TIME-57-002. | 57-002 | AGTM0101 | | AIRGAP-TIME-58-002 | TODO | | SPRINT_510_airgap | AirGap Time Guild, Notifications Guild (src/AirGap/StellaOps.AirGap.Time) | src/AirGap/StellaOps.AirGap.Time | Emit notifications and timeline events when staleness budgets breached or approaching. Dependencies: AIRGAP-TIME-58-001. | | AGTM0101 | @@ -2453,9 +2453,9 @@ | APIGOV-62-001 | TODO | | SPRINT_511_api | API Governance Guild | src/Api/StellaOps.Api.Governance | Build compatibility diff tool producing additive/breaking reports comparing prior release. Dependencies: APIGOV-61-002. | APIGOV-61-002 | APIG0101 | | APIGOV-62-002 | TODO | | SPRINT_511_api | API Governance Guild · DevOps Guild | src/Api/StellaOps.Api.Governance | Automate changelog generation and publish signed artifacts to `src/Sdk/StellaOps.Sdk.Release` pipeline. Dependencies: APIGOV-62-001. | APIGOV-62-001 | APIG0101 | | APIGOV-63-001 | TODO | | SPRINT_511_api | API Governance Guild · Notifications Guild | src/Api/StellaOps.Api.Governance | Integrate deprecation metadata into Notification Studio templates for API sunset events. Dependencies: APIGOV-62-002. | APIGOV-62-002 | APIG0101 | -| ATTEST-01-003 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Requires Excititor ingest evidence | EXCITITOR-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | -| ATTEST-73-001 | TODO | | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Depends on #1 + Concelier graph unblock | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | -| ATTEST-73-002 | TODO | | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Depends on #1 + Concelier graph unblock | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | +| ATTEST-01-003 | DONE (2025-11-23) | 2025-11-23 | SPRINT_110_ingestion_evidence | Excititor Guild · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Excititor attestation payloads shipped on frozen bundle v1. | EXCITITOR-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | +| ATTEST-73-001 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Attestation claims builder verified; TRX archived. | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | +| ATTEST-73-002 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Attestor/StellaOps.Attestor | Internal verify endpoint validated; TRX archived. | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | ATEL0102 | | ATTEST-73-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · Policy Guild | docs/modules/attestor | Wait for ATEL0102 evidence | Wait for ATEL0102 evidence | DOAT0102 | | ATTEST-73-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · Attestor Service Guild | docs/modules/attestor | Depends on #1 | Depends on #1 | DOAT0102 | | ATTEST-74-001 | DOING | | SPRINT_170_notifications_telemetry | Notifications Service Guild · Attestor Service Guild | src/Notify/StellaOps.Notify | Needs DSSE schema sign-off | Needs DSSE schema sign-off | NOTY0102 | @@ -2510,7 +2510,7 @@ | CLI-AIAI-31-002 | DONE | 2025-11-24 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella advise explain` showing conflict narrative and structured rationale. Dependencies: CLI-AIAI-31-001. | — | CLCI0101 | | CLI-AIAI-31-003 | DONE | 2025-11-24 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella advise remediate` generating remediation plans with `--strategy` filters and file output. Dependencies: CLI-AIAI-31-002. | — | CLCI0101 | | CLI-AIAI-31-004 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella advise batch` for summaries/conflicts/remediation with progress + multi-status responses. Dependencies: CLI-AIAI-31-003. | — | CLCI0102 | -| CLI-AIRGAP-56-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001 | PROGRAM-STAFF-1001 | ATMI0102 | +| CLI-AIRGAP-56-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001 | PROGRAM-STAFF-1001 | ATMI0102 | | CLI-AIRGAP-56-002 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Ensure telemetry propagation under sealed mode (no remote exporters) while preserving correlation IDs; add label `AirGapped-Phase-1`. Dependencies: CLI-AIRGAP-56-001. | — | CLCI0102 | | CLI-AIRGAP-57-001 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Add `stella airgap import` with diff preview, bundle scope selection (`--tenant`, `--global`), audit logging, and progress reporting. Dependencies: CLI-AIRGAP-56-002. | — | CLCI0102 | | CLI-AIRGAP-57-002 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Provide `stella airgap seal. Dependencies: CLI-AIRGAP-57-001. | — | CLCI0102 | @@ -2606,7 +2606,7 @@ | CONCELIER-ATTEST-73-001 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Concelier/StellaOps.Concelier.WebService | Attestation claims builder verified; Core/WebService attestation suites green (`TestResults/concelier-attestation/core.trx`, `web.trx`). | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | CCAN0101 | | CONCELIER-ATTEST-73-002 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Core · Evidence Locker Guild | src/Concelier/StellaOps.Concelier.WebService | Internal `/internal/attestations/verify` endpoint validated end-to-end; TRX archived under `TestResults/concelier-attestation/web.trx`. | CONCELIER-AIAI-31-002; ELOCKER-CONTRACT-2001 | CCAN0101 | | CONCELIER-CONSOLE-23-001 | TODO | | SPRINT_112_concelier_i | Concelier WebService Guild · BE-Base Platform Guild | | `/console/advisories` returns grouped linksets with per-source severity/status chips plus `{documentId, observationPath}` provenance references (matching GHSA + Red Hat CVE browser expectations); depends on CONCELIER-LNM-21-201/202. | — | ATLN0102 | -| CONCELIER-CONSOLE-23-001..003 | TODO | | SPRINT_110_ingestion_evidence | Concelier Console Guild | src/Concelier/StellaOps.Concelier.WebService | Console overlays blocked until schema signed off. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002 | CCLN0102 | +| CONCELIER-CONSOLE-23-001..003 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Concelier Console Guild | src/Concelier/StellaOps.Concelier.WebService | Console overlays wired to LNM schema; consumption contract published. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002 | CCLN0102 | | CONCELIER-CONSOLE-23-002 | TODO | | SPRINT_112_concelier_i | Concelier WebService Guild | | Deterministic “new/modified/conflicting” sets referencing linkset IDs and field paths rather than computed verdicts; depends on 23-001. | — | ATLN0102 | | CONCELIER-CONSOLE-23-003 | TODO | | SPRINT_112_concelier_i | Concelier WebService Guild | | CVE/GHSA/PURL lookups return observation excerpts, provenance anchors, and cache hints so tenants can preview evidence safely; reuse structured field taxonomy from Workstream A. | — | ATLN0102 | | CONCELIER-CORE-AOC-19-013 | TODO | | SPRINT_112_concelier_i | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Expand smoke/e2e suites so Authority tokens + tenant headers are mandatory for ingest/read paths (including the new provenance endpoint). Must assert no merge-side effects and that provenance anchors always round-trip. | Must reference AOC guardrails from docs | AGCN0101 | @@ -2673,14 +2673,14 @@ | CONCELIER-WEB-OBS-54-001 | TODO | | SPRINT_117_concelier_vi | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Provide `/attestations/advisories/*` endpoints surfacing DSSE status, verification summary, and provenance chain so CLI/Console can audit trust without hitting databases. Depends on CONCELIER-WEB-OBS-53-001. | Depends on Link-Not-Merge schema (005_ATLN0101) | CNOB0102 | | CONCELIER-WEB-OBS-55-001 | TODO | | SPRINT_117_concelier_vi | Concelier WebService Guild · DevOps Guild | src/Concelier/StellaOps.Concelier.WebService | Implement incident-mode APIs that coordinate ingest, locker, and orchestrator, capturing activation events + cooldown semantics but leaving evidence untouched. Depends on CONCELIER-WEB-OBS-54-001. | Needs #4 to finalize labels | CNOB0102 | | CONN-SUSE-01-003 | Team Excititor Connectors – SUSE | | SPRINT_120_excititor_ii | Connector Guild (SUSE) | src/Excititor/__Libraries/StellaOps.Excititor.Connectors.SUSE.RancherVEXHub | EXCITITOR-CONN-SUSE-01-002; EXCITITOR-POLICY-01-001 | EXCITITOR-CONN-SUSE-01-002; EXCITITOR-POLICY-01-001 | EXCN0102 | -| CONN-TRUST-01-001 | TODO | | SPRINT_110_ingestion_evidence | Excititor + AirGap Guilds | | CONCELIER-GRAPH-21-001/002; ATTEST-PLAN-2001 | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXCN0102 | +| CONN-TRUST-01-001 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Excititor + AirGap Guilds | | Connector trust + air-gap ingest delivered against frozen schema. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXCN0102 | | CONN-UBUNTU-01-003 | Team Excititor Connectors – Ubuntu | | SPRINT_120_excititor_ii | Connector Guild (Ubuntu) | src/Excititor/__Libraries/StellaOps.Excititor.Connectors.Ubuntu.CSAF | EXCITITOR-CONN-UBUNTU-01-002; EXCITITOR-POLICY-01-001 | EXCITITOR-CONN-UBUNTU-01-002; EXCITITOR-POLICY-01-001 | EXCN0102 | | CONSENSUS-LENS-DOCS-0001 | TODO | | SPRINT_332_docs_modules_vex_lens | Docs Guild | docs/modules/vex-lens | Wait for CCSL0101 panel demo | Wait for CCSL0101 panel demo | CCDL0101 | | CONSENSUS-LENS-DOCS-0002 | TODO | 2025-11-05 | SPRINT_332_docs_modules_vex_lens | Docs Guild | docs/modules/vex-lens | Depends on #1 | Depends on #1 | CCDL0101 | | CONSENSUS-LENS-ENG-0001 | TODO | | SPRINT_332_docs_modules_vex_lens | Module Team | docs/modules/vex-lens | Needs CCWO0101 schema | Needs CCWO0101 schema | CCDL0101 | | CONSENSUS-LENS-OPS-0001 | TODO | | SPRINT_332_docs_modules_vex-lens | Ops Guild | docs/modules/vex-lens | Depends on #3 | Depends on #3 | CCDL0101 | | CONSOLE-23-001 | TODO | | SPRINT_112_concelier_i | Console Guild | src/Console/StellaOps.Console | Wait for CCWO0101 schema | Wait for CCWO0101 schema | CCSL0101 | -| CONSOLE-23-001..003 | TODO | | SPRINT_110_ingestion_evidence | Console Guild | src/Console/StellaOps.Console | Depends on #1 | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002 | CCSL0101 | +| CONSOLE-23-001..003 | DONE (2025-11-25) | 2025-11-25 | SPRINT_110_ingestion_evidence | Console Guild | src/Console/StellaOps.Console | Console overlays wired to LNM schema; fixtures published. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002 | CCSL0101 | | CONSOLE-23-002 | TODO | | SPRINT_112_concelier_i | Console Guild | src/Console/StellaOps.Console | Needs LNM graph (CCGH0101) | Needs LNM graph (CCGH0101) | CCSL0101 | | CONSOLE-23-003 | TODO | | SPRINT_112_concelier_i | Console Guild | src/Console/StellaOps.Console | Depends on #3 | Depends on #3 | CCSL0101 | | CONSOLE-23-004 | TODO | | SPRINT_0212_0001_0001_web_i | Console Guild | src/Web/StellaOps.Web | Requires CCPR0101 verdicts | Requires CCPR0101 verdicts | CCSL0101 | @@ -2703,12 +2703,12 @@ | CORE-AOC-19-003 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Depends on #1 | Depends on #1 | EXAC0101 | | CORE-AOC-19-004 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Depends on #2 | Depends on #2 | EXAC0101 | | CORE-AOC-19-013 | TODO | | SPRINT_112_concelier_i | Concelier Core Guild + Excititor | src/Concelier/__Libraries/StellaOps.Concelier.Core | Needs CCAN0101 DSSE output | Needs CCAN0101 DSSE output | EXAC0101 | -| CRT-56-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild | | Wait for PGMI0101 owner | Wait for PGMI0101 owner | MRCR0101 | -| CRT-56-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator · Security Guilds | | Depends on #1 | MIRROR-CRT-56-001; PROV-OBS-53-001 | MRCR0101 | -| CRT-57-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator · AirGap Time Guild | | Needs AIRGAP-TIME-57-001 | MIRROR-CRT-56-001; AIRGAP-TIME-57-001 | MRCR0101 | -| CRT-57-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild | | Depends on #3 | MIRROR-CRT-56-001; AIRGAP-TIME-57-001 | MRCR0101 | -| CRT-58-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator + Evidence Locker | | Requires Evidence Locker contract | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MRCR0101 | -| CRT-58-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator + Security Guild | | Depends on #5 | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MRCR0101 | +| CRT-56-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild | | Wait for PGMI0101 owner | Wait for PGMI0101 owner | MRCR0101 | +| CRT-56-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator · Security Guilds | | Depends on #1 | MIRROR-CRT-56-001; PROV-OBS-53-001 | MRCR0101 | +| CRT-57-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild · AirGap Time Guild | | Needs AIRGAP-TIME-57-001 | MIRROR-CRT-56-001; AIRGAP-TIME-57-001 | MRCR0101 | +| CRT-57-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild | | Depends on #3 | MIRROR-CRT-56-001; AIRGAP-TIME-57-001 | MRCR0101 | +| CRT-58-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator + Evidence Locker | | Requires Evidence Locker contract | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MRCR0101 | +| CRT-58-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator + Security Guild | | Depends on #5 | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MRCR0101 | | CRYPTO-90-001 | DONE | 2025-11-07 | SPRINT_514_sovereign_crypto_enablement | Security Guild (src/__Libraries/StellaOps.Cryptography) | src/__Libraries/StellaOps.Cryptography | | | CRSA0101 | | CRYPTO-90-002 | DONE | 2025-11-07 | SPRINT_514_sovereign_crypto_enablement | Security Guild (src/__Libraries/StellaOps.Cryptography) | src/__Libraries/StellaOps.Cryptography | | | CRSA0101 | | CRYPTO-90-003 | DONE | 2025-11-07 | SPRINT_514_sovereign_crypto_enablement | Security Guild (src/__Libraries/StellaOps.Cryptography) | src/__Libraries/StellaOps.Cryptography | | | CRSA0101 | @@ -2867,31 +2867,32 @@ | DOCS-AIRGAP-58-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · Evidence Locker Guild | docs/modules/airgap | Document `/docs/airgap/portable-evidence.md` for exporting/importing portable evidence bundles across enclaves. Dependencies: DOCS-AIRGAP-58-003. | Requires Evidence Locker attestation notes from 002_ATEL0101 | DOAG0101 | | DOCS-AIRGAP-DEVPORT-64-001 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild · DevPortal Offline Guild | docs/modules/export-center/devportal-offline.md | Create `/docs/airgap/devportal-offline.md` describing offline bundle usage and verification. | Requires #3 draft | DEVL0102 | | DOCS-ATTEST-73-001 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Service Guild (docs) | | Publish `/docs/modules/attestor/overview.md` with imposed rule banner. | — | DOAT0101 | -| DOCS-ATTEST-73-002 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestation Payloads Guild (docs) | | Write `/docs/modules/attestor/payloads.md` with schemas/examples. Dependencies: DOCS-ATTEST-73-001. | — | DOAT0101 | -| DOCS-ATTEST-73-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Policy Guild (docs) | | Publish `/docs/modules/attestor/policies.md` covering verification policies. Dependencies: DOCS-ATTEST-73-002. | — | DOAT0101 | -| DOCS-ATTEST-73-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Service Guild (docs) | | Add `/docs/modules/attestor/workflows.md` detailing ingest, verify, bulk operations. Dependencies: DOCS-ATTEST-73-003. | — | DOAT0101 | -| DOCS-ATTEST-74-001 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, KMS Guild (docs) | | Publish `/docs/modules/attestor/keys-and-issuers.md`. Dependencies: DOCS-ATTEST-73-004. | — | DOAT0101 | -| DOCS-ATTEST-74-002 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Transparency Guild (docs) | | Document `/docs/modules/attestor/transparency.md` with witness usage/offline validation. Dependencies: DOCS-ATTEST-74-001. | — | DOAT0101 | -| DOCS-ATTEST-74-003 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Console Guild (docs) | | Write `/docs/console/attestor-ui.md` with screenshots/workflows. Dependencies: DOCS-ATTEST-74-002. | — | DOAT0101 | -| DOCS-ATTEST-74-004 | TODO | | SPRINT_302_docs_tasks_md_ii | Docs Guild, CLI Attestor Guild (docs) | | Publish `/docs/modules/cli/guides/attest.md` covering CLI usage. Dependencies: DOCS-ATTEST-74-003. | — | DOAT0101 | -| DOCS-ATTEST-75-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, Export Attestation Guild (docs) | | Add `/docs/modules/attestor/airgap.md` for attestation bundles. Dependencies: DOCS-ATTEST-74-004. | — | DOAT0101 | -| DOCS-ATTEST-75-002 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, Security Guild (docs) | | Update `/docs/security/aoc-invariants.md` with attestation invariants. Dependencies: DOCS-ATTEST-75-001. | — | DOAT0101 | +| DOCS-ATTEST-73-002 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestation Payloads Guild (docs) | | Write `/docs/modules/attestor/payloads.md` with schemas/examples. Dependencies: DOCS-ATTEST-73-001. | — | DOAT0101 | +| DOCS-ATTEST-73-003 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Policy Guild (docs) | | Publish `/docs/modules/attestor/policies.md` covering verification policies. Dependencies: DOCS-ATTEST-73-002. | — | DOAT0101 | +| DOCS-ATTEST-73-004 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Service Guild (docs) | | Add `/docs/modules/attestor/workflows.md` detailing ingest, verify, bulk operations. Dependencies: DOCS-ATTEST-73-003. | — | DOAT0101 | +| DOCS-ATTEST-74-001 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, KMS Guild (docs) | | Publish `/docs/modules/attestor/keys-and-issuers.md`. Dependencies: DOCS-ATTEST-73-004. | — | DOAT0101 | +| DOCS-ATTEST-74-002 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Transparency Guild (docs) | | Document `/docs/modules/attestor/transparency.md` with witness usage/offline validation. Dependencies: DOCS-ATTEST-74-001. | — | DOAT0101 | +| DOCS-ATTEST-74-003 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, Attestor Console Guild (docs) | | Write `/docs/console/attestor-ui.md` with screenshots/workflows. Dependencies: DOCS-ATTEST-74-002. | — | DOAT0101 | +| DOCS-ATTEST-74-004 | DONE | 2025-11-23 | SPRINT_302_docs_tasks_md_ii | Docs Guild, CLI Attestor Guild (docs) | | Publish `/docs/modules/cli/guides/attest.md` covering CLI usage. Dependencies: DOCS-ATTEST-74-003. | — | DOAT0101 | +| DOCS-ATTEST-75-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Export Attestation Guild (docs) | | Add `/docs/modules/attestor/airgap.md` for attestation bundles. Dependencies: DOCS-ATTEST-74-004. | — | DOAT0101 | +| DOCS-ATTEST-75-002 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Security Guild (docs) | | Update `/docs/security/aoc-invariants.md` with attestation invariants. Dependencies: DOCS-ATTEST-75-001. | — | DOAT0101 | | DOCS-CLI-41-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, DevEx/CLI Guild (docs) | docs/modules/cli/guides | Publish `/docs/modules/cli/guides/overview.md`, `/docs/modules/cli/guides/configuration.md`, `/docs/modules/cli/guides/output-and-exit-codes.md` with imposed rule statements. | — | DOCL0101 | -| DOCS-CLI-42-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild (docs) | | Publish `/docs/modules/cli/guides/parity-matrix.md` and command guides under `/docs/modules/cli/guides/commands/*.md` (policy, sbom, vuln, vex, advisory, export, orchestrator, notify, aoc, auth). Dependencies: DOCS-CLI-41-001. | — | DOCL0101 | -| DOCS-CLI-DET-01 | TODO | | SPRINT_301_docs_tasks_md_i | Docs Guild · DevEx/CLI Guild | | Document `stella sbomer` verbs (`layer`, `compose`, `drift`, `verify`) with examples & offline instructions. | CLI-SBOM-60-001; CLI-SBOM-60-002 | DOCL0101 | +| DOCS-CLI-42-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild (docs) | | Publish `/docs/modules/cli/guides/parity-matrix.md` and command guides under `/docs/modules/cli/guides/commands/*.md` (policy, sbom, vuln, vex, advisory, export, orchestrator, notify, aoc, auth). Dependencies: DOCS-CLI-41-001. | — | DOCL0101 | +| DOCS-CLI-DET-01 | DONE | 2025-11-23 | SPRINT_301_docs_tasks_md_i | Docs Guild · DevEx/CLI Guild | | Document `stella sbomer` verbs (`layer`, `compose`, `drift`, `verify`) with examples & offline instructions. | CLI-SBOM-60-001; CLI-SBOM-60-002 | DOCL0101 | | DOCS-CLI-FORENSICS-53-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, DevEx/CLI Guild (docs) | docs/modules/cli/guides | Publish `/docs/modules/cli/guides/forensics.md` for snapshot/verify/attest commands with sample outputs, imposed rule banner, and offline workflows. | — | DOCL0101 | | DOCS-CLI-OBS-52-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, DevEx/CLI Guild (docs) | docs/modules/cli/guides | Create `/docs/modules/cli/guides/observability.md` detailing `stella obs` commands, examples, exit codes, imposed rule banner, and scripting tips. | — | DOCL0101 | -| DOCS-CONSOLE-OBS-52-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, Console Guild (docs) | | Document `/docs/console/observability.md` showcasing Observability Hub widgets, trace/log search, imposed rule banner, and accessibility tips. | — | DOCL0101 | -| DOCS-CONSOLE-OBS-52-002 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, Console Guild (docs) | | Publish `/docs/console/forensics.md` covering timeline explorer, evidence viewer, attestation verifier, imposed rule banner, and troubleshooting. Dependencies: DOCS-CONSOLE-OBS-52-001. | — | DOCL0101 | -| DOCS-CONTRIB-62-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, API Governance Guild (docs) | | Publish `/docs/contributing/api-contracts.md` detailing how to edit OAS, lint rules, compatibility checks. | — | DOCL0101 | +| DOCS-CONSOLE-OBS-52-001 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Console Guild (docs) | | Document `/docs/console/observability.md` showcasing Observability Hub widgets, trace/log search, imposed rule banner, and accessibility tips. | Blocked: awaiting Console Observability Hub schemas/widgets from Console Guild | DOCL0101 | +| DOCS-CONSOLE-OBS-52-002 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Console Guild (docs) | | Publish `/docs/console/forensics.md` covering timeline explorer, evidence viewer, attestation verifier, imposed rule banner, and troubleshooting. Dependencies: DOCS-CONSOLE-OBS-52-001. | Blocked: upstream DOCS-CONSOLE-OBS-52-001 | DOCL0101 | +| DOCS-OBS-50-002 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild, Security Guild (docs) | docs/observability | Author `/docs/observability/telemetry-standards.md` detailing common fields, scrubbing policy, sampling defaults, and redaction override procedure. | Docs Guild, Security Guild (docs) | DOOB0101 | +| DOCS-CONTRIB-62-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, API Governance Guild (docs) | | Publish `/docs/contributing/api-contracts.md` detailing how to edit OAS, lint rules, compatibility checks. | — | DOCL0101 | | DOCS-DETER-70-002 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Scanner Guild | docs/modules/scanner/determinism.md | Document the scanner determinism score process (`determinism.json` schema, CI harness, replay instructions) under `/docs/modules/scanner/determinism-score.md` and add a release-notes template entry. Dependencies: SCAN-DETER-186-010, DEVOPS-SCAN-90-004. | Need deterministic suite notes from 137_SCDT0101 | DOSC0101 | -| DOCS-DEVPORT-62-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild, Developer Portal Guild (docs) | | Document `/docs/devportal/publishing.md` for build pipeline, offline bundle steps. | — | DOCL0101 | +| DOCS-DEVPORT-62-001 | DONE | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild, Developer Portal Guild (docs) | | Document `/docs/devportal/publishing.md` for build pipeline, offline bundle steps. | — | DOCL0101 | | DOCS-DSL-401-005 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | Docs Guild (`docs/policy/dsl.md`, `docs/policy/lifecycle.md`) | `docs/policy/dsl.md`, `docs/policy/lifecycle.md` | Refresh `docs/policy/dsl.md` + lifecycle docs with the new syntax, signal dictionary (`trust_score`, `reachability`, etc.), authoring workflow, and safety rails (shadow mode, coverage tests). | — | DOCL0101 | | DOCS-ENTROPY-70-004 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Scanner Guild | docs/modules/scanner/determinism.md | Publish entropy analysis documentation (scoring heuristics, JSON schemas, policy hooks, UI guidance) under `docs/modules/scanner/entropy.md` and update trust-lattice references. Dependencies: SCAN-ENTROPY-186-011/012, POLICY-RISK-90-001. | Requires entropy guardrails from 078_SCSA0301 | DOSC0101 | -| DOCS-EXC-25-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Author `/docs/governance/exceptions.md` covering lifecycle, scope patterns, examples, compliance checklist. | CLEX0101 outputs | DOEX0102 | -| DOCS-EXC-25-002 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Publish `/docs/governance/approvals-and-routing.md` detailing roles, routing matrix, MFA rules, audit trails. Dependencies: DOCS-EXC-25-001. | CLEX0101 | DOEX0102 | -| DOCS-EXC-25-003 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Create `/docs/api/exceptions.md` with endpoints, payloads, errors, idempotency notes. Dependencies: DOCS-EXC-25-002. | UIEX0101 | DOEX0102 | -| DOCS-EXC-25-005 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs + Accessibility Guilds | docs/modules/excititor | Write `/docs/ui/exception-center.md` with UI walkthrough, badges, accessibility, shortcuts. Dependencies: DOCS-EXC-25-003. | UIEX0101 | DOEX0102 | +| DOCS-EXC-25-001 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Author `/docs/governance/exceptions.md` covering lifecycle, scope patterns, examples, compliance checklist. | Blocked: waiting on CLEX0101 exception governance spec and UI workflow | DOEX0102 | +| DOCS-EXC-25-002 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Publish `/docs/governance/approvals-and-routing.md` detailing roles, routing matrix, MFA rules, audit trails. Dependencies: DOCS-EXC-25-001. | Blocked: upstream DOCS-EXC-25-001 | DOEX0102 | +| DOCS-EXC-25-003 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Create `/docs/api/exceptions.md` with endpoints, payloads, errors, idempotency notes. Dependencies: DOCS-EXC-25-002. | Blocked: upstream DOCS-EXC-25-002 | DOEX0102 | +| DOCS-EXC-25-005 | BLOCKED | 2025-11-25 | SPRINT_303_docs_tasks_md_iii | Docs + Accessibility Guilds | docs/modules/excititor | Write `/docs/ui/exception-center.md` with UI walkthrough, badges, accessibility, shortcuts. Dependencies: DOCS-EXC-25-003. | Blocked: upstream DOCS-EXC-25-003 | DOEX0102 | | DOCS-EXC-25-006 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild | docs/modules/excititor | Update `/docs/modules/cli/guides/exceptions.md` covering command usage and exit codes. Dependencies: DOCS-EXC-25-005. | CLEX0101 | DOEX0102 | | DOCS-EXC-25-007 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · DevOps Guild | docs/modules/excititor | Publish `/docs/migration/exception-governance.md` describing cutover from legacy suppressions, notifications, rollback. Dependencies: DOCS-EXC-25-006. | UIEX0101 & Ops runbooks | DOEX0102 | | DOCS-EXPORT-37-004 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Export Center Guild | docs/modules/export-center | Publish `/docs/security/export-hardening.md` outlining RBAC, tenancy, encryption, redaction, restating imposed rule. | Wait for ATMI0102 orchestration notes | DOEC0102 | @@ -2910,19 +2911,19 @@ | DOCS-GRAPH-24-007 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · DevOps Guild | docs/modules/graph | Produce `/docs/migration/graph-parity.md` with rollout plan, parity checks, fallback guidance. Dependencies: DOCS-GRAPH-24-006. | Depends on DVDO0108 deployment notes | DOGR0101 | | DOCS-INSTALL-44-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/overview.md` and `/docs/install/compose-quickstart.md` with imposed rule line and copy-ready commands. | Need DVPL0101 compose schema | DOIS0101 | | DOCS-INSTALL-45-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/helm-prod.md` and `/docs/install/configuration-reference.md` with values tables and imposed rule reminder. Dependencies: DOCS-INSTALL-44-001. | Wait for updated TLS guidance from 127_SIGR0101 | DOIS0101 | -| DOCS-INSTALL-46-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/airgap.md`, `/docs/security/supply-chain.md`, `/docs/operations/health-and-readiness.md`, `/docs/release/image-catalog.md`, `/docs/console/onboarding.md` (each with imposed rule). Dependencies: DOCS-INSTALL-45-001. | Depends on 126_RLRC0101 replay hooks | DOIS0101 | -| DOCS-INSTALL-50-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · DevOps Guild | docs/install | Add `/docs/install/telemetry-stack.md` with collector deployment, exporter options, offline kit notes, and imposed rule banner. Dependencies: DOCS-INSTALL-46-001. | Requires DevOps offline validation (DVDO0107) | DOIS0101 | +| DOCS-INSTALL-46-001 | BLOCKED | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Deployment Guild | docs/install | Publish `/docs/install/airgap.md`, `/docs/security/supply-chain.md`, `/docs/operations/health-and-readiness.md`, `/docs/release/image-catalog.md`, `/docs/console/onboarding.md` (each with imposed rule). Dependencies: DOCS-INSTALL-45-001. | Blocked: upstream DOCS-INSTALL-45-001 and 126_RLRC0101 replay hooks | DOIS0101 | +| DOCS-INSTALL-50-001 | BLOCKED | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · DevOps Guild | docs/install | Add `/docs/install/telemetry-stack.md` with collector deployment, exporter options, offline kit notes, and imposed rule banner. Dependencies: DOCS-INSTALL-46-001. | Blocked: upstream DOCS-INSTALL-46-001; awaiting DevOps offline validation (DVDO0107) | DOIS0101 | | DOCS-LNM-22-001 | BLOCKED | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs Guild · Concelier Guild | docs/modules/concelier/link-not-merge.md | Author `/docs/advisories/aggregation.md` covering observation vs linkset, conflict handling, AOC requirements, and reviewer checklist. | Need final schema text from 005_ATLN0101 | DOLN0101 | | DOCS-LNM-22-002 | BLOCKED | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs Guild · Excititor Guild | docs/modules/concelier/link-not-merge.md | Publish `/docs/vex/aggregation.md` describing VEX observation/linkset model, product matching, conflicts. Dependencies: DOCS-LNM-22-001. | Waiting on Excititor overlay notes | DOLN0101 | | DOCS-LNM-22-003 | BLOCKED | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs Guild · BE-Base Guild | docs/modules/concelier/link-not-merge.md | Update `/docs/api/advisories.md` and `/docs/api/vex.md` for new endpoints, parameters, errors, exports. Dependencies: DOCS-LNM-22-002. | Replay hook contract from RBBN0101 | DOLN0101 | -| DOCS-LNM-22-004 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Policy Guild | docs/modules/concelier/link-not-merge.md | Create `/docs/policy/effective-severity.md` detailing severity selection strategies from multiple sources. Dependencies: DOCS-LNM-22-003. | Requires policy binding from PLVL0102 | DOLN0101 | +| DOCS-LNM-22-004 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Policy Guild | docs/modules/concelier/link-not-merge.md | Create `/docs/policy/effective-severity.md` detailing severity selection strategies from multiple sources. Dependencies: DOCS-LNM-22-003. | Requires policy binding from PLVL0102 | DOLN0101 | | DOCS-LNM-22-005 | BLOCKED | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs Guild · UI Guild | docs/modules/concelier/link-not-merge.md | Document `/docs/ui/evidence-panel.md` with screenshots, conflict badges, accessibility guidance. Dependencies: DOCS-LNM-22-004. | UI signals from 124_CCSL0101 | DOLN0101 | -| DOCS-LNM-22-007 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Observability Guild | docs/modules/concelier/link-not-merge.md | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. Dependencies: DOCS-LNM-22-005. | Observability wiring from 066_PLOB0101 | DOLN0101 | +| DOCS-LNM-22-007 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Observability Guild | docs/modules/concelier/link-not-merge.md | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. Dependencies: DOCS-LNM-22-005. | Observability wiring from 066_PLOB0101 | DOLN0101 | | DOCS-LNM-22-008 | DONE (2025-11-03) | 2025-11-03 | SPRINT_117_concelier_vi | Docs Guild · DevOps Guild | docs/modules/concelier/link-not-merge.md | Documented Link-Not-Merge migration plan in `docs/migration/no-merge.md`; keep synced with ongoing tasks. | Needs retrospective summary | DOLN0101 | -| DOCS-NOTIFY-40-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Security Guild | docs/modules/notify | Publish `/docs/notifications/channels.md`, `/docs/notifications/escalations.md`, `/docs/notifications/api.md`, `/docs/operations/notifier-runbook.md`, `/docs/security/notifications-hardening.md`; each ends with imposed rule line. | Need tenancy + throttling updates from DVDO0110 | DONO0101 | -| DOCS-OAS-61-001 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · API Contracts Guild | docs/api/oas | Publish `/docs/api/overview.md` covering auth, tenancy, pagination, idempotency, rate limits with banner. | Need governance decisions from 049_APIG0101 | DOOA0101 | -| DOCS-OAS-61-002 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · API Governance Guild | docs/api/oas | Author `/docs/api/conventions.md` capturing naming, errors, filters, sorting, examples. Dependencies: DOCS-OAS-61-001. | Requires review board inputs (APIG0101) | DOOA0101 | -| DOCS-OAS-61-003 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · API Governance Guild | docs/api/oas | Publish `/docs/api/versioning.md` describing SemVer, deprecation headers, migration playbooks. Dependencies: DOCS-OAS-61-002. | Waiting on lint/tooling export from DVDO0108 | DOOA0101 | +| DOCS-NOTIFY-40-001 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · Security Guild | docs/modules/notify | Publish `/docs/notifications/channels.md`, `/docs/notifications/escalations.md`, `/docs/notifications/api.md`, `/docs/operations/notifier-runbook.md`, `/docs/security/notifications-hardening.md`; each ends with imposed rule line. | Need tenancy + throttling updates from DVDO0110 | DONO0101 | +| DOCS-OAS-61-001 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · API Contracts Guild | docs/api/overview.md | Publish `/docs/api/overview.md` covering auth, tenancy, pagination, idempotency, rate limits with banner. | Need governance decisions from 049_APIG0101 | DOOA0101 | +| DOCS-OAS-61-002 | BLOCKED | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · API Governance Guild | docs/api/oas | Author `/docs/api/conventions.md` capturing naming, errors, filters, sorting, examples. Dependencies: DOCS-OAS-61-001. | Blocked: awaiting governance inputs (APIG0101) and example approvals | DOOA0101 | +| DOCS-OAS-61-003 | DONE | 2025-11-25 | SPRINT_305_docs_tasks_md_v | Docs Guild · API Governance Guild | docs/api/oas | Publish `/docs/api/versioning.md` describing SemVer, deprecation headers, migration playbooks. Dependencies: DOCS-OAS-61-002. | Waiting on lint/tooling export from DVDO0108 | DOOA0101 | | DOCS-OAS-62-001 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · DevPortal Guild | docs/api/oas | Stand up `/docs/api/reference/` auto-generated site; integrate with portal nav. Dependencies: DOCS-OAS-61-003. | Needs DevPortal publishing hooks (050_DEVL0101) | DOOA0101 | | DOCS-OBS-50-002 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · Security Guild | docs/observability | Author `/docs/observability/telemetry-standards.md` detailing common fields, scrubbing policy, sampling defaults, and redaction override procedure. | Need console metric list from 059_CNOB0101 | DOOB0101 | | DOCS-OBS-50-003 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · Observability Guild | docs/observability | Create `/docs/observability/logging.md` covering structured log schema, dos/don'ts, tenant isolation, and copyable examples. Dependencies: DOCS-OBS-50-002. | Waiting on observability ADR from 066_PLOB0101 | DOOB0101 | @@ -3102,13 +3103,13 @@ | ENGINE-50-007 | TODO | | SPRINT_126_policy_reasoning | Policy + Scheduler Worker Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | POLICY-ENGINE-50-006 | POLICY-ENGINE-50-006 | DOPE0105 | | ENGINE-60-001 | TODO | | SPRINT_126_policy_reasoning | Policy + SBOM Service Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | POLICY-ENGINE-50-007 | POLICY-ENGINE-50-007 | DOPE0105 | | ENGINE-60-002 | TODO | | SPRINT_126_policy_reasoning | Policy + BE-Base Platform Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | POLICY-ENGINE-60-001 | POLICY-ENGINE-60-001 | DOPE0105 | -| ENGINE-66-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Baseline collections + indexes doc. | — | DORG0101 | +| ENGINE-66-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Baseline collections + indexes doc. | — | DORG0101 | | ENGINE-66-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-66-001 | RISK-ENGINE-66-001 | DORG0101 | | ENGINE-67-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + Concelier Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-66-002 | RISK-ENGINE-66-002 | DORG0101 | -| ENGINE-67-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Excititor Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-001 | RISK-ENGINE-67-001 | DORG0101 | -| ENGINE-67-003 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Policy Engine Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-002 | RISK-ENGINE-67-002 | DORG0101 | +| ENGINE-67-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + Excititor Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-001 | RISK-ENGINE-67-001 | DORG0101 | +| ENGINE-67-003 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + Policy Engine Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-002 | RISK-ENGINE-67-002 | DORG0101 | | ENGINE-68-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + Findings Ledger Guilds / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-67-003 | RISK-ENGINE-67-003 | DORG0101 | -| ENGINE-68-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + API Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-68-001 | RISK-ENGINE-68-001 | DORG0101 | +| ENGINE-68-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk + API Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-68-001 | RISK-ENGINE-68-001 | DORG0101 | | ENGINE-69-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Policy Studio Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-68-002 | RISK-ENGINE-68-002 | DORG0101 | | ENGINE-69-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Observability Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-69-001 | RISK-ENGINE-69-001 | DORG0101 | | ENGINE-70-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk + Export Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | RISK-ENGINE-69-002 | RISK-ENGINE-69-002 | DORG0101 | @@ -3148,11 +3149,11 @@ | EXCITITOR-AIAI-31-002 | DONE | 2025-11-17 | SPRINT_0119_0001_0001_excititor_i | Excititor Web/Core Guilds | src/Excititor/StellaOps.Excititor.WebService | Chunk API streaming raw statements + signature metadata with tenant/policy filters. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ELOCKER-CONTRACT-2001 | EXAI0101 | | EXCITITOR-AIAI-31-003 | DONE | 2025-11-17 | SPRINT_0119_0001_0001_excititor_i | Excititor Observability Guild | src/Excititor/StellaOps.Excititor.WebService | Telemetry/guardrail metrics (counters, chunk histograms, signature failure + AOC guard meters); traces pending span sink. | EXCITITOR-AIAI-31-002 | EXAI0101 | | EXCITITOR-AIAI-31-004 | DONE | 2025-11-18 | SPRINT_0119_0001_0001_excititor_i | Docs Guild · Excititor Guild | docs/modules/excititor/evidence-contract.md | Advisory-AI evidence contract + determinism guarantees and storage mapping. | 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 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Air-gap ingest parity delivered; connector trust enforced. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 | | EXCITITOR-AIRGAP-56-001 | DOING (2025-11-22) | 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 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Time-anchor import path aligned with Evidence Locker contract. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 | | EXCITITOR-AIRGAP-57-001 | DONE (2025-11-24) | 2025-11-22 | 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 | +| EXCITITOR-AIRGAP-58 | DONE (2025-11-22) | 2025-11-22 | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Import/export automation delivered for frozen schema. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 | | EXCITITOR-AIRGAP-58-001 | DONE (2025-11-24) | 2025-11-22 | SPRINT_0119_0001_0001_excititor_i | Excititor Core + Evidence Locker Guilds | src/Excititor/__Libraries/StellaOps.Excititor.Core | Package tenant-scoped VEX evidence (raw JSON, normalization diff, provenance) into portable bundles tied to timeline events so Advisory AI can hydrate contexts in sealed environments. Depends on EXCITITOR-AIRGAP-57-001. | EXCITITOR-AIRGAP-58 | EXAG0101 | | EXCITITOR-ATTEST-01-003 | DONE | 2025-11-17 | SPRINT_0119_0001_0001_excititor_i | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Attestation verifier harness + diagnostics prove DSSE bundle verification without consensus logic. | EXCITITOR-AIAI-31-002; ELOCKER-CONTRACT-2001 | EXAT0101 | | EXCITITOR-ATTEST-73-001 | DONE | 2025-11-17 | SPRINT_0119_0001_0001_excititor_i | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Attestation payloads emitted with supplier identity, justification summary, and scope metadata for trust chaining. | EXCITITOR-ATTEST-01-003 | EXAT0101 | @@ -3160,9 +3161,9 @@ | EXCITITOR-CONN-SUSE-01-003 | TODO | | SPRINT_120_excititor_ii | Excititor Guild (SUSE connector) | src/Excititor/__Libraries/StellaOps.Excititor.Connectors.SUSE.RancherVEXHub | DONE (2025-11-09) – Emit provider trust configuration (signer fingerprints, trust tier notes) into the raw provenance envelope so downstream VEX Lens/Policy components can weigh issuers. Connector must not apply weighting or consensus inside ingestion. | EXCITITOR-CONN-SUSE-01-002; EXCITITOR-POLICY-01-001 | EXCN0101 | | EXCITITOR-CONN-TRUST-01-001 | DONE | 2025-11-20 | SPRINT_0119_0001_0001_excititor_i | Excititor Guild · AirGap Guilds | src/Excititor/__Libraries/StellaOps.Excititor.Connectors* | Signer metadata loader/enricher wired for MSRC/Oracle/Ubuntu/OpenVEX connectors; env `STELLAOPS_CONNECTOR_SIGNER_METADATA_PATH`; docs + sample hash shipped. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXCN0101 | | EXCITITOR-CONN-UBUNTU-01-003 | TODO | | SPRINT_120_excititor_ii | Excititor Guild (Ubuntu connector) | src/Excititor/__Libraries/StellaOps.Excititor.Connectors.Ubuntu.CSAF | DONE (2025-11-09) – Emit Ubuntu signing metadata (GPG fingerprints, issuer trust tier) inside raw provenance artifacts so downstream Policy/VEX Lens consumers can weigh issuers. Connector must remain aggregation-only with no inline weighting. | EXCITITOR-CONN-UBUNTU-01-002 | EXCN0101 | -| EXCITITOR-CONSOLE-23-001 | TODO | | SPRINT_120_excititor_ii | Excititor Guild · Docs Guild | src/Excititor/StellaOps.Excititor.WebService | Expose `/console/vex` endpoints returning grouped VEX statements per advisory/component with status chips, justification metadata, precedence trace pointers, and tenant-scoped filters for Console explorer. Dependencies: EXCITITOR-LNM-21-201, EXCITITOR-LNM-21-202. | DOCN0101 | EXCO0101 | -| EXCITITOR-CONSOLE-23-002 | TODO | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Provide aggregated counts for VEX overrides (new, not_affected, revoked) powering Console dashboard + live status ticker; emit metrics for policy explain integration. Dependencies: EXCITITOR-CONSOLE-23-001, EXCITITOR-LNM-21-203. | EXCITITOR-CONSOLE-23-001 | EXCO0101 | -| EXCITITOR-CONSOLE-23-003 | TODO | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Deliver rapid lookup endpoints of VEX by advisory/component for Console global search; ensure response includes provenance and precedence context; include caching and RBAC. Dependencies: EXCITITOR-CONSOLE-23-001. | EXCITITOR-CONSOLE-23-001 | EXCO0101 | +| EXCITITOR-CONSOLE-23-001 | DONE (2025-11-23) | | SPRINT_120_excititor_ii | Excititor Guild · Docs Guild | src/Excititor/StellaOps.Excititor.WebService | Expose `/console/vex` endpoints returning grouped VEX statements per advisory/component with status chips, justification metadata, precedence trace pointers, and tenant-scoped filters for Console explorer. Dependencies: EXCITITOR-LNM-21-201, EXCITITOR-LNM-21-202. | DOCN0101 | EXCO0101 | +| EXCITITOR-CONSOLE-23-002 | DONE (2025-11-23) | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Provide aggregated counts for VEX overrides (new, not_affected, revoked) powering Console dashboard + live status ticker; emit metrics for policy explain integration. Dependencies: EXCITITOR-CONSOLE-23-001, EXCITITOR-LNM-21-203. | EXCITITOR-CONSOLE-23-001 | EXCO0101 | +| EXCITITOR-CONSOLE-23-003 | DONE (2025-11-23) | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Deliver rapid lookup endpoints of VEX by advisory/component for Console global search; ensure response includes provenance and precedence context; include caching and RBAC. Dependencies: EXCITITOR-CONSOLE-23-001. | EXCITITOR-CONSOLE-23-001 | EXCO0101 | | EXCITITOR-CORE-AOC-19-002 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Implement deterministic extraction of advisory IDs, component PURLs, and references into `linkset`, capturing reconciled-from metadata for traceability. | Link-Not-Merge schema | EXCA0101 | | EXCITITOR-CORE-AOC-19-003 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Enforce `(vendor, upstreamId, contentHash, tenant)` uniqueness, generate supersedes chains, and ensure append-only versioning of raw VEX documents. Dependencies: EXCITITOR-CORE-AOC-19-002. | EXCITITOR-CORE-AOC-19-002 | EXCA0101 | | EXCITITOR-CORE-AOC-19-004 | TODO | | SPRINT_120_excititor_ii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Excise consensus/merge/severity logic from Excititor ingestion paths, updating exports/tests to rely on Policy Engine materializations instead. Dependencies: EXCITITOR-CORE-AOC-19-003. | EXCITITOR-CORE-AOC-19-003 | EXCA0101 | @@ -3173,13 +3174,13 @@ | EXCITITOR-GRAPH-21-001 | TODO | 2025-10-27 | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Provide batched VEX/advisory reference fetches keyed by graph node PURLs so UI inspector can display raw documents and justification metadata. | Link-Not-Merge schema | EXGR0101 | | EXCITITOR-GRAPH-21-002 | TODO | 2025-10-27 | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Ensure overlay metadata includes VEX justification summaries and document versions for Cartographer overlays; update fixtures/tests. Dependencies: EXCITITOR-GRAPH-21-001. | EXCITITOR-GRAPH-21-001 | EXGR0101 | | EXCITITOR-GRAPH-21-005 | TODO | 2025-10-27 | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | Add indexes/materialized views for VEX lookups by PURL/policy to support Cartographer inspector performance; document migrations. Dependencies: EXCITITOR-GRAPH-21-002. | EXCITITOR-GRAPH-21-002 | EXGR0101 | -| EXCITITOR-GRAPH-24-101 | TODO | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Provide endpoints delivering VEX status summaries per component/asset for Vuln Explorer integration. Dependencies: EXCITITOR-GRAPH-21-005. | EXCITITOR-GRAPH-21-002 | EXGR0101 | -| EXCITITOR-GRAPH-24-102 | TODO | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Add batch VEX observation retrieval optimized for Graph overlays/tooltips. Dependencies: EXCITITOR-GRAPH-24-101. | EXCITITOR-GRAPH-24-101 | EXGR0101 | +| EXCITITOR-GRAPH-24-101 | DONE (2025-11-25) | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Provide endpoints delivering VEX status summaries per component/asset for Vuln Explorer integration. Dependencies: EXCITITOR-GRAPH-21-005. | EXCITITOR-GRAPH-21-002 | EXGR0101 | +| EXCITITOR-GRAPH-24-102 | DONE (2025-11-25) | | SPRINT_120_excititor_ii | Excititor Guild | src/Excititor/StellaOps.Excititor.WebService | Add batch VEX observation retrieval optimized for Graph overlays/tooltips. Dependencies: EXCITITOR-GRAPH-24-101. | EXCITITOR-GRAPH-24-101 | EXGR0101 | | EXCITITOR-LNM-21-001 | TODO | | SPRINT_121_excititor_iii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | Stand up `vex_observations` and `vex_linksets` collections with shard keys, tenant guards, and migrations that retire any residual merge-era data without mutating raw content. | Link-Not-Merge schema | EXLN0101 | | EXCITITOR-LNM-21-002 | TODO | | SPRINT_121_excititor_iii | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Capture disagreement metadata (status + justification deltas) directly inside linksets with confidence scores so downstream consumers can highlight conflicts without Excititor choosing winners. Depends on EXCITITOR-LNM-21-001. | EXCITITOR-LNM-21-001 | EXLN0101 | | EXCITITOR-LNM-21-003 | TODO | | SPRINT_121_excititor_iii | Excititor Core + Platform Events Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Emit `vex.linkset.updated` events and describe payload shape (observation ids, confidence, conflict summary) so Policy/Lens/UI can subscribe while Excititor stays aggregation-only. Depends on EXCITITOR-LNM-21-002. | EXCITITOR-LNM-21-002 | EXLN0101 | -| EXCITITOR-LNM-21-201 | TODO | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Ship `/vex/observations` read endpoints with filters for advisory/product/issuer, strict RBAC, and deterministic pagination (no derived verdict fields). Depends on EXCITITOR-LNM-21-003. | EXCITITOR-LNM-21-001 | EXLN0101 | -| EXCITITOR-LNM-21-202 | TODO | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Provide `/vex/linksets` + export endpoints that surface alias mappings, conflict markers, and provenance proofs exactly as stored; errors must map to `ERR_AGG_*`. Depends on EXCITITOR-LNM-21-201. | EXCITITOR-LNM-21-201 | EXLN0101 | +| EXCITITOR-LNM-21-201 | DONE (2025-11-25) | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Ship `/vex/observations` read endpoints with filters for advisory/product/issuer, strict RBAC, and deterministic pagination (no derived verdict fields). Depends on EXCITITOR-LNM-21-003. | EXCITITOR-LNM-21-001 | EXLN0101 | +| EXCITITOR-LNM-21-202 | DONE (2025-11-25) | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Provide `/vex/linksets` + export endpoints that surface alias mappings, conflict markers, and provenance proofs exactly as stored; errors must map to `ERR_AGG_*`. Depends on EXCITITOR-LNM-21-201. | EXCITITOR-LNM-21-201 | EXLN0101 | | EXCITITOR-LNM-21-203 | TODO | | SPRINT_121_excititor_iii | Excititor WebService Guild | src/Excititor/StellaOps.Excititor.WebService | Update OpenAPI, SDK smoke tests, and documentation to cover the new observation/linkset endpoints with realistic examples Advisory AI/Lens teams can rely on. Depends on EXCITITOR-LNM-21-202. | EXCITITOR-LNM-21-202 | EXLN0101 | | EXCITITOR-OBS-51-001 | TODO | | SPRINT_121_excititor_iii | Excititor Core Guild · DevOps Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Publish ingest latency, scope resolution success, conflict rate, and signature verification metrics plus SLO burn alerts so we can prove Excititor meets the AOC “evidence freshness” mission. | Wait for 046_TLTY0101 span schema | EXOB0101 | | EXCITITOR-OBS-52-001 | TODO | | SPRINT_122_excititor_iv | Excititor Core Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Emit `timeline_event` entries for every ingest/linkset change with trace IDs, justification summaries, and evidence hashes so downstream systems can replay the raw facts chronologically. Depends on EXCITITOR-OBS-51-001. | Needs #1 merged for correlation IDs | EXOB0101 | @@ -3234,7 +3235,7 @@ | EXPORT-OAS-63 | TODO | | SPRINT_160_export_evidence | Exporter Service Guild · API Governance Guild | | Needs API governance sign-off (049_APIG0101) | Needs API governance sign-off (049_APIG0101) | AGEX0101 | | EXPORT-OAS-63-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild · SDK Guild | src/ExportCenter/StellaOps.ExportCenter | Implement deprecation headers and notifications for legacy export endpoints. Dependencies: EXPORT-OAS-62-001. | Requires #3 schema | AGEX0101 | | EXPORT-OBS-50-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild · Observability Guild | src/ExportCenter/StellaOps.ExportCenter | Adopt telemetry core in exporter service + workers, ensuring spans/logs capture profile id, tenant, artifact counts, distribution type, and trace IDs. | Wait for telemetry schema drop from 046_TLTY0101 | ECOB0101 | -| EXPORT-OBS-51-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | Downstream automation awaiting assembler staffing outcome. | PROGRAM-STAFF-1001 | ECOB0101 | +| EXPORT-OBS-51-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | Downstream automation awaiting assembler staffing outcome. | PROGRAM-STAFF-1001 | ECOB0101 | | EXPORT-OBS-52-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild | src/ExportCenter/StellaOps.ExportCenter | Publish timeline events for export lifecycle (`export.requested`, `export.built`, `export.distributed`, `export.failed`) embedding manifest hashes and evidence refs. Provide dedupe + retry logic. Dependencies: EXPORT-OBS-51-001. | Requires shared middleware from task #1 | ECOB0101 | | EXPORT-OBS-53-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild · Evidence Locker Guild | src/ExportCenter/StellaOps.ExportCenter | Push export manifests + distribution transcripts to evidence locker bundles, ensuring Merkle root alignment and DSSE pre-sign data available. Dependencies: EXPORT-OBS-52-001. | Blocked on Evidence Locker DSSE API (002_ATEL0101) | ECOB0101 | | EXPORT-OBS-54-001 | TODO | | SPRINT_163_exportcenter_ii | Exporter Service Guild · Provenance Guild | src/ExportCenter/StellaOps.ExportCenter | Produce DSSE attestations for each export artifact and distribution target, expose verification API `/exports/{id}/attestation`, and integrate with CLI verify path. Dependencies: EXPORT-OBS-53-001. | PROGRAM-STAFF-1001; EXPORT-MIRROR-ORCH-1501 | ECOB0101 | @@ -3401,12 +3402,12 @@ | LNM-22-005 | BLOCKED (2025-10-27) | 2025-10-27 | SPRINT_305_docs_tasks_md_v | Docs + UI Guild | | Docs update for UI flows. | DOCS-LNM-22-004 | IMPT0101 | | LNM-22-007 | TODO | | SPRINT_305_docs_tasks_md_v | Docs Guild · Observability Guild | docs/modules/concelier/link-not-merge.md | Publish `/docs/observability/aggregation.md` with metrics/traces/logs/SLOs. Dependencies: DOCS-LNM-22-005. | DOCS-LNM-22-005 | DOLN0102 | | LNM-22-008 | DONE | 2025-11-03 | SPRINT_117_concelier_vi | Docs Guild · DevOps Guild | docs/modules/concelier/link-not-merge.md | Document Link-Not-Merge migration playbook updates in `docs/migration/no-merge.md`, including rollback guidance. | LNM-22-007 | DOLN0102 | -| MIRROR-CRT-56-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild | | Deterministic assembler has no owner; kickoff rescheduled to 2025-11-15. | PROGRAM-STAFF-1001 | ATMI0101 | -| MIRROR-CRT-56-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator · Security Guilds | | DSSE/TUF metadata follows assembler baseline. | MIRROR-CRT-56-001; MIRROR-DSSE-REV-1501; PROV-OBS-53-001 | ATMI0101 | -| MIRROR-CRT-57-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild · AirGap Time Guild | | OCI/time-anchor workstreams blocked pending assembler + time contract. | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | ATMI0101 | -| MIRROR-CRT-57-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild · AirGap Time Guild | | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | ATMI0101 | -| MIRROR-CRT-58-001 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild · CLI Guild · Exporter Guild | | CLI + Export automation depends on assembler and DSSE/TUF track. | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | ATMI0101 | -| MIRROR-CRT-58-002 | TODO | | SPRINT_110_ingestion_evidence | Mirror Creator Guild · CLI Guild · Exporter Guild | | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | ATMI0101 | +| MIRROR-CRT-56-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild | | Deterministic assembler has no owner; kickoff rescheduled to 2025-11-15. | PROGRAM-STAFF-1001 | ATMI0101 | +| MIRROR-CRT-56-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator · Security Guilds | | DSSE/TUF metadata follows assembler baseline. | MIRROR-CRT-56-001; MIRROR-DSSE-REV-1501; PROV-OBS-53-001 | ATMI0101 | +| MIRROR-CRT-57-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild · AirGap Time Guild | | OCI/time-anchor workstreams blocked pending assembler + time contract. | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | ATMI0101 | +| MIRROR-CRT-57-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild · AirGap Time Guild | | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | MIRROR-CRT-56-001; AIRGAP-TIME-CONTRACT-1501; AIRGAP-TIME-57-001 | ATMI0101 | +| MIRROR-CRT-58-001 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild · CLI Guild · Exporter Guild | | CLI + Export automation depends on assembler and DSSE/TUF track. | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | ATMI0101 | +| MIRROR-CRT-58-002 | TODO | | SPRINT_0506_ops_devops_iv | Mirror Creator Guild · CLI Guild · Exporter Guild | | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | MIRROR-CRT-56-001; EXPORT-OBS-54-001; CLI-AIRGAP-56-001 | ATMI0101 | | MTLS-11-002 | DONE | 2025-11-08 | SPRINT_100_identity_signing | Authority Core & Security Guild | src/Authority/StellaOps.Authority | Refresh grants enforce original client cert, tokens persist `x5t#S256` metadata, docs updated. | AUTH-DPOP-11-001 | AUIN0102 | | NATIVE-401-015 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | Scanner Worker Guild | `src/Scanner/__Libraries/StellaOps.Scanner.Symbols.Native`, `src/Scanner/__Libraries/StellaOps.Scanner.CallGraph.Native` | Bootstrap Symbols.Native + CallGraph.Native scaffolding and coverage fixtures. | Needs replay requirements from DORR0101 | SCNA0101 | | NOTIFY-38-001 | TODO | | SPRINT_214_web_iii | BE-Base Platform Guild | src/Web/StellaOps.Web | Route approval/rule APIs through Web gateway with tenant scopes. | Wait for NOTY0103 approval payload schema | NOWB0101 | @@ -3458,13 +3459,13 @@ | OBS-50-002 | DOING | | SPRINT_170_notifications_telemetry | Telemetry Core Guild | | Roll out collectors/helm overlays + regression tests for exporters. | Needs 50-001 baseline in main | | | OBS-50-003 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · Observability Guild | | Update collector deployment + metrics catalog docs. | Needs scrubber decisions from TLTY0102 | | | OBS-50-004 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild · Observability Guild | | Add SOP for telemetry scrub policies + troubleshooting. | Requires 50-003 outline | | -| OBS-51-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | Build SLO bus + queue depth metrics feeding CLI/exporter dashboards. | PROGRAM-STAFF-1001 | | +| OBS-51-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | Build SLO bus + queue depth metrics feeding CLI/exporter dashboards. | PROGRAM-STAFF-1001 | | | OBS-51-002 | TODO | | SPRINT_170_notifications_telemetry | Telemetry Core Guild · Observability Guild | | Enable shadow-mode evaluators + roll into main collectors. | Depends on 51-001 shadow mode | | | OBS-52-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Emit ingest latency/queue/AOC metrics with burn-rate alerts. | Needs ATLN0101 schema | | | OBS-52-002 | TODO | | SPRINT_160_export_evidence | Timeline Indexer Guild | | Configure streaming pipeline (retention/partitioning/backpressure). | Needs Concelier metrics | | | OBS-52-003 | TODO | | SPRINT_160_export_evidence | Timeline Indexer Guild | | Add CI validation + schema enforcement for timeline events. | Depends on 52-002 | | | OBS-52-004 | TODO | | SPRINT_160_export_evidence | Timeline Indexer + Security Guilds | | Harden stream (auth, encryption) + produce DSSE proofs. | Requires 52-003 outputs | | -| OBS-53-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | Establish provenance SLO signals + exporter hooks. | PROGRAM-STAFF-1001 | | +| OBS-53-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | Establish provenance SLO signals + exporter hooks. | PROGRAM-STAFF-1001 | | | OBS-53-002 | TODO | | SPRINT_0513_0001_0001_provenance | Provenance + Security Guild | src/Provenance/StellaOps.Provenance.Attestation | Add attestation metrics/log scrubbers in Provenance.Attestation. | Depends on 53-001 | | | OBS-53-003 | TODO | | SPRINT_0513_0001_0001_provenance | Provenance Guild | src/Provenance/StellaOps.Provenance.Attestation | Ship dashboards/tests proving attestation observability. | Requires 53-002 outputs | | | OBS-54-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild · Provenance Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Needs shared exporter from 1039_EXPORT-OBS-54-001 | Needs shared exporter from 1039_EXPORT-OBS-54-001 | CNOB0101 | @@ -3757,7 +3758,7 @@ | RISK-ENGINE-67-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Excitor Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Integrate VEX gate provider and ensure gating short-circuits scoring as configured | RISK-ENGINE-67-001 | | | RISK-ENGINE-67-003 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Policy Engine Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Add fix availability, asset criticality, and internet exposure providers with caching + TTL enforcement | RISK-ENGINE-67-002 | | | RISK-ENGINE-68-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Findings Ledger Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Persist scoring results + explanation pointers to Findings Ledger; handle incremental updates via input hash | RISK-ENGINE-67-003 | | -| RISK-ENGINE-68-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, API Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Expose APIs | RISK-ENGINE-68-001 | | +| RISK-ENGINE-68-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, API Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Expose APIs | RISK-ENGINE-68-001 | | | RISK-ENGINE-69-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Policy Studio Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Implement simulation mode producing distributions and top movers without mutating ledger | RISK-ENGINE-68-002 | | | RISK-ENGINE-69-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Observability Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Add telemetry | RISK-ENGINE-69-001 | | | RISK-ENGINE-70-001 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Risk Engine Guild, Export Guild / src/RiskEngine/StellaOps.RiskEngine | src/RiskEngine/StellaOps.RiskEngine | Support offline provider bundles with manifest verification and missing-data reporting | RISK-ENGINE-69-002 | | @@ -4172,7 +4173,7 @@ | TEN-49-001 | TODO | | SPRINT_205_cli_v | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | | | | | TEST-186-006 | TODO | | SPRINT_186_record_deterministic_execution | Signing Guild, QA Guild (`src/Signer/StellaOps.Signer.Tests`) | `src/Signer/StellaOps.Signer.Tests` | | | | | TEST-62-001 | TODO | | SPRINT_310_docs_tasks_md_x | Docs Guild, Contract Testing Guild (docs) | | | | | -| TIME-57-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | | PROGRAM-STAFF-1001 | | +| TIME-57-001 | TODO | | SPRINT_503_ops_devops_i | Exporter Guild · AirGap Time Guild · CLI Guild | | | PROGRAM-STAFF-1001 | | | TIME-57-002 | TODO | | SPRINT_510_airgap | Exporter Guild · AirGap Time Guild · CLI Guild | src/AirGap/StellaOps.AirGap.Time | PROGRAM-STAFF-1001 | PROGRAM-STAFF-1001 | AGTM0101 | | TIME-58-001 | TODO | | SPRINT_510_airgap | AirGap Time Guild | src/AirGap/StellaOps.AirGap.Time | AIRGAP-TIME-58-001 | AIRGAP-TIME-58-001 | AGTM0101 | | TIME-58-002 | TODO | | SPRINT_510_airgap | AirGap Time Guild · Notifications Guild | src/AirGap/StellaOps.AirGap.Time | TIME-58-001 | TIME-58-001 | AGTM0101 | @@ -4267,7 +4268,7 @@ | VULN-29-012 | TODO | | SPRINT_311_docs_tasks_md_xi | Docs Guild, Ops Guild (docs) | | | | | | VULN-29-013 | TODO | | SPRINT_311_docs_tasks_md_xi | Docs Guild, Deployment Guild (docs) | | | | | | VULN-API-29-001 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Define OpenAPI spec (list/detail/query/simulation/workflow/export), query JSON schema, pagination/grouping contracts, and error codes | | PLVA0101 | -| VULN-API-29-002 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Implement list/query endpoints with policy parameter, grouping, server paging, caching, and cost budgets | VULN-API-29-001 | PLVA0101 | +| VULN-API-29-002 | DONE | 2025-11-25 | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Implement list/query endpoints with policy parameter, grouping, server paging, caching, and cost budgets; tests at `tests/TestResults/vuln-explorer/api.trx`. | VULN-API-29-001 | PLVA0101 | | VULN-API-29-003 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Implement detail endpoint aggregating evidence, policy rationale, paths | VULN-API-29-002 | PLVA0101 | | VULN-API-29-004 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild, Findings Ledger Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Expose workflow endpoints | VULN-API-29-003 | PLVA0101 | | VULN-API-29-005 | TODO | | SPRINT_0129_0001_0001_policy_reasoning | Vuln Explorer API Guild, Policy Guild / src/VulnExplorer/StellaOps.VulnExplorer.Api | src/VulnExplorer/StellaOps.VulnExplorer.Api | Implement simulation endpoint comparing `policy_from` vs `policy_to`, returning diffs without side effects; hook into Policy Engine batch eval | VULN-API-29-004 | PLVA0101 | @@ -4400,3 +4401,18 @@ | ZASTAVA-SURFACE-02 | TODO | | SPRINT_136_scanner_surface | Zastava Observer Guild (src/Zastava/StellaOps.Zastava.Observer) | src/Zastava/StellaOps.Zastava.Observer | Use Surface manifest reader helpers to resolve `cas://` pointers and enrich drift diagnostics with manifest provenance. | SURFACE-FS-02; ZASTAVA-SURFACE-01 | | | guard unit tests` | TODO | | SPRINT_116_concelier_v | QA Guild (src/Concelier/StellaOps.Concelier.WebService) | src/Concelier/StellaOps.Concelier.WebService | Add unit tests for schema validators, forbidden-field guards (`ERR_AOC_001/2/6/7`), and supersedes chains to keep ingestion append-only. Depends on CONCELIER-WEB-AOC-19-002. | | | | store wiring` | TODO | | SPRINT_113_concelier_ii | Concelier Storage Guild (src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo) | src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo | Move large raw payloads to object storage with deterministic pointers, update bootstrapper/offline kit seeds, and guarantee provenance metadata remains intact. Depends on CONCELIER-LNM-21-102. | | NOTY0105 | +| DOCS-OBS-50-003 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild, Observability Guild (docs) | docs/observability | Create `/docs/observability/logging.md` covering structured log schema, dos/don'ts, tenant isolation, and copyable examples. Dependencies: DOCS-OBS-50-002. | Waiting on observability ADR from 066_PLOB0101 | DOOB0101 | +| DOCS-OBS-50-003 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild, Observability Guild (docs) | | Create `/docs/observability/logging.md` covering structured log schema, dos/don'ts, tenant isolation, and copyable examples. Dependencies: DOCS-OBS-50-002. | Waiting on observability ADR from 066_PLOB0101 | DOOB0101 | +| DOCS-OBS-50-004 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild, Observability Guild (docs) | | Draft `/docs/observability/tracing.md` explaining context propagation, async linking, CLI header usage, and sampling strategies. Dependencies: DOCS-OBS-50-003. | — | DOOB0101 | +| DOCS-OBS-51-001 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild, DevOps Guild (docs) | | Publish `/docs/observability/metrics-and-slos.md` cataloging metrics, SLO targets, burn rate policies, and alert runbooks. Dependencies: DOCS-OBS-50-004. | — | DOOB0101 | +| DOCS-ORCH-32-001 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/orchestrator/overview.md | Author `/docs/orchestrator/overview.md` covering mission, roles, AOC alignment, governance, with imposed rule reminder. | — | DOOR0102 | +| DOCS-ORCH-32-002 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/orchestrator/architecture.md | Author `/docs/orchestrator/architecture.md` detailing scheduler, DAGs, rate limits, data model, message bus, storage layout, restating imposed rule. Dependencies: DOCS-ORCH-32-001. | — | DOOR0102 | +| DOCS-ORCH-33-001 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/orchestrator/api.md | Publish `/docs/orchestrator/api.md` (REST/WebSocket endpoints, payloads, error codes) with imposed rule note. Dependencies: DOCS-ORCH-32-002. | — | DOOR0102 | +| DOCS-ORCH-33-002 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/orchestrator/console.md | Publish `/docs/orchestrator/console.md` covering screens, a11y, live updates, control actions, reiterating imposed rule. Dependencies: DOCS-ORCH-33-001. | — | DOOR0102 | +| DOCS-ORCH-33-003 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/orchestrator/cli.md | Publish `/docs/orchestrator/cli.md` documenting commands, options, exit codes, streaming output, offline usage, and imposed rule. Dependencies: DOCS-ORCH-33-002. | — | DOOR0102 | +| DOCS-ORCH-34-001 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/orchestrator/run-ledger.md | Author `/docs/orchestrator/run-ledger.md` covering ledger schema, provenance chain, audit workflows, with imposed rule reminder. Dependencies: DOCS-ORCH-33-003. | — | DOOR0102 | +| DOCS-ORCH-34-002 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/security/secrets-handling.md | Update `/docs/security/secrets-handling.md` for orchestrator KMS refs, redaction badges, operator hygiene, reiterating imposed rule. Dependencies: DOCS-ORCH-34-001. | — | DOOR0102 | +| DOCS-ORCH-34-003 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/operations/orchestrator-runbook.md | Publish `/docs/operations/orchestrator-runbook.md` (incident playbook, backfill guide, circuit breakers, throttling) with imposed rule statement. Dependencies: DOCS-ORCH-34-002. | — | DOOR0102 | +| DOCS-ORCH-34-004 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/schemas/artifacts.md | Document `/docs/schemas/artifacts.md` describing artifact kinds, schema versions, hashing, storage layout, restating imposed rule. Dependencies: DOCS-ORCH-34-003. | — | DOOR0102 | +| DOCS-ORCH-34-005 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | docs/slo/orchestrator-slo.md | Author `/docs/slo/orchestrator-slo.md` defining SLOs, burn alerts, measurement, and reiterating imposed rule. Dependencies: DOCS-ORCH-34-004. | — | DOOR0102 | +| DOCS-OAS-62-001 | DONE (2025-11-25) | | SPRINT_306_docs_tasks_md_vi | Docs Guild, Developer Portal Guild (docs) | docs/api/reference/README.md | Stand up `/docs/api/reference/` auto-generated site; integrate with portal nav. Dependencies: DOCS-OAS-61-003. | — | DOOA0101 | diff --git a/docs/modules/attestor/airgap.md b/docs/modules/attestor/airgap.md new file mode 100644 index 000000000..ec40fd2c9 --- /dev/null +++ b/docs/modules/attestor/airgap.md @@ -0,0 +1,42 @@ +# Attestor Air-Gap Guide (DOCS-ATTEST-75-001) + +Last updated: 2025-11-25 + +## Goal +Run attestation verification entirely offline while keeping determinism and tenant safety intact. + +## Inputs & prerequisites +- **Trust bundle**: DSSE signing keys + certificate chains packaged under `out/offline/attestor/trust-bundle/` (hash manifest included). +- **Transparency checkpoints (optional)**: Rekor or equivalent checkpoints mirrored to `out/offline/attestor/transparency/`. +- **Authority scopes**: `attest:verify` and tenant scoping (`X-Stella-Tenant`) are still required even in sealed mode. +- **No external calls**: Outbound network must be disabled; attestor uses only the provided bundles. + +## Configuration (sealed mode) +Set the following environment flags on WebService/Worker: +- `Attestor__Offline__Enabled=true` +- `Attestor__TrustBundlePath=/app/offline/trust-bundle` +- `Attestor__Transparency__CheckpointPath=/app/offline/transparency` (optional) +- `Attestor__Verification__DisableHttpFetch=true` + +Mount the bundle directories read-only; keep hashes alongside the payloads for audit. + +## Verification flow (offline) +1. Client submits a DSSE envelope to `/api/v1/attestations/verify` with tenant header. +2. Service loads keys from the offline trust bundle; issuer lookup is strictly local. +3. If transparency data is present, the server verifies inclusion against the mirrored checkpoint; otherwise it records `transparency=skipped` in the rationale. +4. Result is returned with deterministic fields: `subject`, `statementDigest`, `verified=true|false`, `transparency=passed|skipped|failed`, `rationale[]`. + +## Determinism safeguards +- All hashes are lowercase hex; timestamps are UTC ISO-8601. +- Sorting: multiple statements are ordered by `subject` then `statementDigest`. +- No network retries or clock drift compensation; rely on bundle timestamps. + +## Operations checklist +- [ ] Refresh trust bundle hashes before each deploy; compare against signed manifest. +- [ ] Rotate keys by replacing the bundle atomically; restart workers to pick up changes. +- [ ] Record verification results in the delivery ledger for replay/audit. + +## Related docs +- `docs/modules/attestor/overview.md` +- `docs/modules/attestor/keys-and-issuers.md` +- `docs/modules/attestor/transparency.md` diff --git a/docs/modules/excititor/operations/graph-linkouts-implementation.md b/docs/modules/excititor/operations/graph-linkouts-implementation.md index 4dd1cc7f7..88f66258c 100644 --- a/docs/modules/excititor/operations/graph-linkouts-implementation.md +++ b/docs/modules/excititor/operations/graph-linkouts-implementation.md @@ -1,4 +1,4 @@ -# Excititor · Graph Linkouts & Overlays — Implementation Notes (Graph 21-001/002/005) +# Excititor · Graph Linkouts & Overlays — Implementation Notes (Graph 21-001/002/005/24-101/24-102) - **Date:** 2025-11-21 - **Scope:** EXCITITOR-GRAPH-21-001, EXCITITOR-GRAPH-21-002, EXCITITOR-GRAPH-21-005 @@ -14,6 +14,14 @@ - `GET /v1/graph/overlays?purl=&purl=&includeJustifications=true|false` - Response per PURL: `summary` counts (`open`, `not_affected`, `under_investigation`, `no_statement`), `latestModifiedAt`, `justifications[]` (unique, sorted), `provenance` (`sources[]`, `lastEvidenceHash`), `cached`, `cacheAgeMs`. +3) **Status summaries (24-101)** + - `GET /v1/graph/status?purl=&purl=` + - Response mirrors overlay summaries but omits justification payloads; includes `sources[]`, `lastEvidenceHash`, `cached`, `cacheAgeMs`. Intended for Vuln Explorer status colouring. + +4) **Batch observations for tooltips (24-102)** + - `GET /v1/graph/observations?purl=[&purl=...]&includeJustifications=true|false[&limitPerPurl=50][&cursor=]` + - Response per PURL: ordered `observations[]` (`observationId`, `advisoryId`, `status`, `justification?`, `providerId`, `modifiedAt`, `evidenceHash`, `dsseEnvelopeHash?`) plus `truncated`; top-level `nextCursor`, `hasMore` enable paging. Limits enforced per PURL and globally. + ## Storage & Indexes (21-005) - `vex_observations` indexes: - `{ tenant: 1, component.purl: 1, advisoryId: 1, source: 1, modifiedAt: -1 }` @@ -28,6 +36,8 @@ - `excititor:graph:overlayTtlSeconds` (default 300) - `excititor:graph:maxPurls` (default 500) - `excititor:graph:maxAdvisoriesPerPurl` (default 200) +- `excititor:graph:maxTooltipItemsPerPurl` (default 50) +- `excititor:graph:maxTooltipTotal` (default 1000) ## Telemetry - Counter `excititor.graph.linkouts.requests` tags: `tenant`, `includeJustifications`, `includeProvenance`. diff --git a/docs/modules/excititor/operations/vex-raw-validator.md b/docs/modules/excititor/operations/vex-raw-validator.md new file mode 100644 index 000000000..ba47275f0 --- /dev/null +++ b/docs/modules/excititor/operations/vex-raw-validator.md @@ -0,0 +1,31 @@ +# Excititor · VEX Raw Collection Validator (AOC-19-001/002) + +- **Date:** 2025-11-25 +- **Scope:** EXCITITOR-STORE-AOC-19-001 / 19-002 +- **Working directory:** `src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo` + +## What shipped +- `$jsonSchema` validator applied to `vex_raw` (migration `20251125-vex-raw-json-schema`) with `validationAction=warn`, `validationLevel=moderate` to surface contract violations without impacting ingestion. +- Schema lives at `docs/modules/excititor/schemas/vex_raw.schema.json` (mirrors Mongo validator fields: digest/id, providerId, format, sourceUri, retrievedAt, optional content/GridFS object id, metadata strings). +- Migration is auto-registered in DI; hosted migration runner applies it on service start. New collections created with the validator if missing. + +## How to run (online/offline) +1) Ensure Excititor WebService/Worker starts with Mongo credentials that allow `collMod`. +2) Validator applies automatically via migration runner. To force manually: + ```bash + mongosh "$MONGO_URI" --eval 'db.runCommand({collMod:"vex_raw", validator:'$(cat docs/modules/excititor/schemas/vex_raw.schema.json)', validationAction:"warn", validationLevel:"moderate"})' + ``` +3) Offline kit: bundle `docs/modules/excititor/schemas/vex_raw.schema.json` with release artifacts; ops can apply via `mongosh` or `mongo` offline against snapshots. + +## Rollback / relax +- To relax validation (e.g., hotfix window): `db.runCommand({collMod:"vex_raw", validator:{}, validationAction:"warn", validationLevel:"off"})`. +- Reapplying the migration restores the schema. + +## Compatibility notes +- Validator keeps `additionalProperties=true` to avoid blocking future fields; required set is minimal to guarantee provenance + content hash presence. +- Action is `warn` to avoid breaking existing feeds; flip to `error` once downstream datasets are clean. + +## Acceptance +- Contract + schema captured. +- Migration in code and auto-applied. +- Rollback path documented. diff --git a/docs/modules/excititor/schemas/vex_raw.schema.json b/docs/modules/excititor/schemas/vex_raw.schema.json new file mode 100644 index 000000000..6a308ca1a --- /dev/null +++ b/docs/modules/excititor/schemas/vex_raw.schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://stellaops.dev/schemas/excititor/vex_raw.schema.json", + "title": "Excititor VEX Raw Document", + "type": "object", + "additionalProperties": true, + "required": ["_id", "providerId", "format", "sourceUri", "retrievedAt", "digest"], + "properties": { + "_id": { + "type": "string", + "description": "Content-addressed digest; equals `digest`." + }, + "providerId": { "type": "string", "minLength": 1 }, + "format": { "type": "string", "enum": ["csaf", "cyclonedx", "openvex"] }, + "sourceUri": { "type": "string", "minLength": 1 }, + "retrievedAt": { "type": "string", "format": "date-time" }, + "digest": { "type": "string", "minLength": 32 }, + "content": { + "oneOf": [ + { "type": "string", "contentEncoding": "base64" }, + { "type": "string" } + ], + "description": "Inline payload if below GridFS threshold; may be empty when stored in GridFS." + }, + "gridFsObjectId": { + "anyOf": [ + { "type": "string" }, + { "type": "null" } + ] + }, + "metadata": { + "type": "object", + "additionalProperties": { "type": "string" } + } + } +} diff --git a/docs/notifications/api.md b/docs/notifications/api.md new file mode 100644 index 000000000..3f451599c --- /dev/null +++ b/docs/notifications/api.md @@ -0,0 +1,42 @@ +# Notifications API + +> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied. + +Last updated: 2025-11-25 (Docs Tasks Md.V · DOCS-NOTIFY-40-001) + +All endpoints require `Authorization: Bearer ` and `X-Stella-Tenant` header. Responses use the common error envelope (`docs/api/overview.md`). Paths are rooted at `/api/v1/notify`. + +## Channels +- `POST /channels` — create channel. Body matches `notifications/channels.md` schema. Returns `201` + channel. +- `GET /channels` — list channels (deterministic order: type ASC, id ASC). Supports `type` filter. +- `GET /channels/{id}` — fetch single channel. +- `DELETE /channels/{id}` — soft-delete; fails if referenced by active rules unless `force=true` query. + +## Rules +- `POST /rules` — create/update rule; idempotency via `Idempotency-Key`. +- `GET /rules` — list rules with paging (`page_token`, `page_size`). Sorted by `name` ASC. +- `POST /rules:preview` — dry-run rule against sample event; returns matched actions and rendered templates. + +## Policies & escalations +- `POST /policies/escalations` — create escalation policy (see `notifications/escalations.md`). +- `GET /policies/escalations` — list policies. + +## Deliveries & digests +- `GET /deliveries` — query delivery ledger; filters: `status`, `channel`, `rule_id`, `from`, `to`. Sorted by `createdUtc` DESC then `id` ASC. +- `GET /deliveries/{id}` — single delivery with rendered payload hash and attempts. +- `POST /digests/preview` — preview digest rendering for a tenant/rule set; returns deterministic body/hash without sending. + +## Acknowledgements +- `POST /acks/{token}` — acknowledge an escalation token. Validates DSSE signature, token expiry, and tenant. Returns `200` with cancellation summary. + +## Simulations +- `POST /simulations/rules` — simulate a rule set for a supplied event payload; no side effects. Returns matched actions and throttling outcome. + +## Health & metadata +- `GET /health` — liveness/readiness probes. +- `GET /metadata` — returns supported channel types, max payload sizes, and server version. + +## Determinism notes +- All list endpoints are stable and include `next_page_token` when applicable. +- Templates render with fixed locale `en-US` unless `Accept-Language` provided; rendering is pure (no network calls). +- `bodyHash` uses SHA-256 over canonical JSON; repeated sends with identical inputs produce identical hashes and are de-duplicated. diff --git a/docs/notifications/channels.md b/docs/notifications/channels.md new file mode 100644 index 000000000..56270d553 --- /dev/null +++ b/docs/notifications/channels.md @@ -0,0 +1,51 @@ +# Notification Channels + +> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied. + +Last updated: 2025-11-25 (Docs Tasks Md.V · DOCS-NOTIFY-40-001) + +## Supported channel types +- **Slack / Teams**: webhook-based with optional slash-command ack URLs. +- **Email (SMTP/SMTPS)**: relay-only; secrets provided via `secretRef` in Authority. +- **Generic webhook**: signed (HMAC-SHA256) payloads with replay protection and allowlisted hosts. +- **Pager duty-style escalation webhooks**: same contract as generic webhooks but with escalation metadata. +- **Console in-app**: stored delivery rendered in UI; always enabled for each tenant. + +## Channel resource schema (Notify API) +```json +{ + "id": "uuid", + "tenant": "string", + "type": "slack|teams|email|webhook|pager|console", + "endpoint": "https://..." , + "secretRef": "authority://secrets/notify/slack-hook", // optional per type + "labels": { "env": "prod", "team": "sre" }, + "throttle": { "windowSeconds": 60, "max": 10 }, + "quietHours": { "from": "22:00", "to": "06:00", "timezone": "UTC" }, + "enabled": true, + "createdUtc": "2025-11-25T00:00:00Z" +} +``` +- **Determinism**: channel ids are UUIDv5 seeded by `(tenant, type, endpoint)` when created via manifests; server generates new IDs for ad-hoc API calls. +- **Validation**: endpoints must be on the allowlist; secretRef must exist in Authority; quiet hours use 24h clock UTC. + +## Connector rules +- No secrets are stored in Notify DB; only `secretRef` is persisted. +- Per-tenant allowlists control outbound hostnames/ports; defaults block public internet in air-gapped kits. +- Payload signing: + - Slack/Teams: bearer secret in URL (indirect via secretRef) plus optional HMAC header `X-Stella-Signature` for mirror validation. + - Webhook/Pager: HMAC `X-Stella-Signature` (hex) over body with nonce + timestamp; receivers must enforce 5‑minute skew. + +## Offline posture +- Offline kits ship default channel manifests under `out/offline/notify/channels/*.json` with placeholder endpoints. +- Operators must replace endpoints and secretRefs before deploy; validation rejects placeholder values. + +## Observability +- Emit `notify.channel.delivery` counter with tags: `channel_type`, `tenant`, `status` (success/fail/throttled/quiet_hours), `rule_id`. +- Store delivery attempt hashes in the delivery ledger; duplicate payloads are de-duplicated per `(channel, bodyHash)` for 24h. + +## Safety checklist +- [ ] Endpoint on allowlist and TLS valid. +- [ ] `secretRef` exists in Authority and scoped to tenant. +- [ ] Quiet hours configured for non-critical alerts; throttles set for bursty rules. +- [ ] HMAC signing verified in downstream system (webhook/pager). diff --git a/docs/notifications/escalations.md b/docs/notifications/escalations.md new file mode 100644 index 000000000..d07a89818 --- /dev/null +++ b/docs/notifications/escalations.md @@ -0,0 +1,51 @@ +# Escalations & Acknowledgements + +> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied. + +Last updated: 2025-11-25 (Docs Tasks Md.V · DOCS-NOTIFY-40-001) + +## Model +- **Escalation policy**: ordered stages of channels with delays; stored per tenant. +- **Acknowledgement**: DSSE-signed token embedded in messages; acknowledger must present token to stop escalation. +- **Suppression**: rules may mark events as non-escalating (informational) while still sending single notifications. + +## Policy schema (conceptual) +```json +{ + "id": "uuid", + "tenant": "string", + "name": "pager-policy-prod", + "stages": [ + { "delaySeconds": 0, "channels": ["slack-prod", "email-oncall"] }, + { "delaySeconds": 900, "channels": ["pager-primary"] }, + { "delaySeconds": 1800,"channels": ["pager-management"] } + ], + "autoCloseMinutes": 120, + "retry": { "maxAttempts": 3, "backoffSeconds": 60 } +} +``` +- Stages execute sequentially until an **ack** is recorded. +- Deterministic ordering: channels within a stage are sorted lexicographically before dispatch. + +## Ack tokens +- Token payload: `{ tenant, deliveryId, expiresUtc, ruleId, actionHash }`. +- Signed with Authority-issued DSSE key; verified by Notify WebService before accepting `POST /acks/{token}`. +- Expiry defaults to 24h; tokens are single-use and idempotent. + +## Escalation flow +1) Rule fires → action references an escalation policy. +2) Stage 0 deliveries sent; ledger records attempts and ack URL. +3) If no ack by `delaySeconds`, next stage dispatches; repeats until ack or final stage. +4) On ack, remaining stages are cancelled; ledger entry marked `acknowledged` with timestamp and subject. + +## Quiet hours & throttles +- Quiet hours suppress *new* escalations; in-flight escalations continue. +- Per-policy throttle prevents repeated escalation runs for identical `actionHash` within a configurable window (default 30m). + +## Observability +- Counters: `notify.escalation.started`, `notify.escalation.stage_sent`, `notify.escalation.ack`, `notify.escalation.cancelled` tagged by `tenant`, `policy`, `stage`. +- Logs: structured `escalation.{started|stage_sent|ack|cancelled}` with delivery ids and rationale. + +## Runbooks +- Update escalation policy safely: create new policy id, switch rules, then delete old policy to avoid mid-flight ambiguity. +- If a stage storms, set throttle higher or add quiet hours; do not delete the policy mid-flight—use `cancelEscalation` endpoint instead. diff --git a/docs/observability/aggregation.md b/docs/observability/aggregation.md new file mode 100644 index 000000000..ae90b6f9a --- /dev/null +++ b/docs/observability/aggregation.md @@ -0,0 +1,37 @@ +# Aggregation Observability + +Last updated: 2025-11-25 (Docs Tasks Md.V · DOCS-LNM-22-007) + +Covers metrics, traces, and logs for Link-Not-Merge (LNM) aggregation and evidence pipelines. + +## Metrics +- `aggregation_ingest_latency_seconds` (histogram) — end-to-end ingest per statement; labels: `tenant`, `source`, `status`. +- `aggregation_conflict_total` (counter) — conflicts encountered; labels: `tenant`, `advisory`, `product`, `reason`. +- `aggregation_overlay_cache_hits_total` / `_misses_total` — overlay cache effectiveness; labels: `tenant`, `cache`. +- `aggregation_vex_gate_total` — VEX gating outcomes; labels: `tenant`, `status` (`affected`, `not_affected`, `unknown`). +- `aggregation_queue_depth` (gauge) — pending statements per tenant. + +## Traces +- Span name `aggregation.process` with attributes: + - `tenant`, `advisory`, `product`, `vex_status`, `source_kind` + - `overlay_version`, `cache_hit` (bool) +- Link to upstream ingest span (`traceparent` forwarded by Excititor/Concelier). +- Export to OTLP; sampling default 10% outside prod, 100% for `status=error`. + +## Logs +Structured JSON with fields: `tenant`, `advisory`, `product`, `vex_status`, `decision` (`merged|suppressed|dropped`), `reason`, `duration_ms`, `trace_id`. + +## SLOs +- **Ingest latency**: p95 < 500ms per statement (steady state). +- **Cache hit rate**: >80% for overlays; alerts when below for 15 minutes. +- **Error rate**: <0.1% over 10 minute window. + +## Alerts +- `HighConflictRate` — `aggregation_conflict_total` delta > 100/minute per tenant. +- `QueueBacklog` — `aggregation_queue_depth` > 10k for 5 minutes. +- `LowCacheHit` — overlay cache hit rate < 60% for 10 minutes. + +## Offline/air-gap considerations +- Export metrics to local Prometheus scrape; no external sinks. +- Trace sampling and log retention configured via environment without needing control-plane access. +- Deterministic ordering preserved; cache warmers seeded from bundled fixtures. diff --git a/docs/observability/logging.md b/docs/observability/logging.md new file mode 100644 index 000000000..7a9609206 --- /dev/null +++ b/docs/observability/logging.md @@ -0,0 +1,41 @@ +# Logging Standards (DOCS-OBS-50-003) + +Last updated: 2025-11-25 (Docs Tasks Md.VI) + +## Goals +- Deterministic, structured logs for all services. +- Keep tenant safety and redaction guarantees while enabling search, correlation, and offline analysis. + +## Log shape (JSON) +Required fields: +- `timestamp` (UTC ISO-8601) +- `tenant`, `workload` (service name), `env`, `region`, `version` +- `level` (`debug|info|warn|error|fatal`) +- `category` (logger/category name), `operation` (verb/action) +- `trace_id`, `span_id`, `correlation_id` (if external) +- `message` (concise, no secrets) +- `status` (`ok|error|fault|throttle`) +- `error.code`, `error.message` (redacted), `retryable` (bool) when status != ok + +Optional but recommended: +- `resource` (subject id/purl/path when safe), `http.method`, `http.status_code`, `duration_ms`, `host`, `pid`, `thread`. + +## Redaction rules +- Never log Authorization headers, tokens, passwords, private keys, full request/response bodies. +- Redact to `"[redacted]"` and add `redaction.reason` (`secret|pii|policy`). +- Hash low-cardinality identifiers when needed (`sha256` hex) and mark `hashed=true`. + +## Determinism & offline posture +- Stable key ordering not required, but field set must be consistent per log type. +- No external enrichment; rely on bundled metadata (service map, tenant labels). +- All times UTC; newline-delimited JSON (NDJSON); LF line endings. + +## Sampling & rate limits +- Info logs rate-limited per component (default 100/s); warn/error/fatal never sampled. +- Structured audit logs (`category=audit`) are never sampled and must include `actor`, `action`, `target`, `result`. + +## Validation checklist +- [ ] Required fields present and non-empty. +- [ ] No secrets/PII; redaction markers recorded. +- [ ] Correlation fields (`trace_id`, `span_id`) set when spans exist. +- [ ] Log level matches outcome (errors use warn/error/fatal only). diff --git a/docs/observability/metrics-and-slos.md b/docs/observability/metrics-and-slos.md new file mode 100644 index 000000000..7eb0c9db1 --- /dev/null +++ b/docs/observability/metrics-and-slos.md @@ -0,0 +1,42 @@ +# Metrics & SLOs (DOCS-OBS-51-001) + +Last updated: 2025-11-25 (Docs Tasks Md.VI) + +## Core metrics (platform-wide) +- **Requests**: `http_requests_total{tenant,workload,route,status}` (counter); latency histogram `http_request_duration_seconds`. +- **Jobs**: `worker_jobs_total{tenant,queue,status}`; `worker_job_duration_seconds`. +- **DB**: `db_query_duration_seconds{db,operation}`; `db_pool_in_use`, `db_pool_available`. +- **Cache**: `cache_requests_total{result=hit|miss}`; `cache_latency_seconds`. +- **Queue depth**: `queue_depth{tenant,queue}` (gauge). +- **Errors**: `errors_total{tenant,workload,code}`. +- **Custom module metrics**: keep namespaced (e.g., `riskengine_score_duration_seconds`, `notify_delivery_attempts_total`). + +## SLOs (suggested) +- API availability: 99.9% monthly per public service. +- P95 latency: <300 ms for read endpoints; <1 s for write endpoints. +- Worker job success: >99% over 30d; P95 job duration set per queue (document locally). +- Queue backlog: alert when `queue_depth` > 1000 for 5 minutes per tenant/queue. +- Error budget policy: 28-day rolling window; burn-rate alerts at 2× and 14× budget. + +## Alert examples +- High error rate: `rate(errors_total[5m]) / rate(http_requests_total[5m]) > 0.02`. +- Latency regression: `histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le,route)) > 0.3`. +- Queue backlog: `queue_depth > 1000` for 5m. +- Job failures: `rate(worker_jobs_total{status="failed"}[10m]) > 0.01`. + +## Observability hygiene +- Tag everything with `tenant`, `workload`, `env`, `region`, `version`. +- Keep metric names stable; prefer adding labels over renaming. +- No high-cardinality labels (avoid `user_id`, `path`, raw errors); bucket or hash if needed. +- Offline: scrape locally (Prometheus/OTLP); ship exports via bundle if required. + +## Dashboards +- Golden signals per service: traffic, errors, saturation, latency (P50/P95/P99). +- Queue dashboards: depth, age, throughput, success/fail rates. +- Tracing overlays: link span `status` to error metrics; use exemplars where supported. + +## Validation checklist +- [ ] Metrics emitted with required tags. +- [ ] Cardinality review completed (no unbounded labels). +- [ ] Alerts wired to error budget policy. +- [ ] Dashboards cover golden signals and queue health. diff --git a/docs/observability/telemetry-standards.md b/docs/observability/telemetry-standards.md new file mode 100644 index 000000000..1304634f5 --- /dev/null +++ b/docs/observability/telemetry-standards.md @@ -0,0 +1,38 @@ +# Telemetry Standards (DOCS-OBS-50-002) + +Last updated: 2025-11-25 (Docs Tasks Md.VI) + +## Common envelope +- **Trace context**: `trace_id`, `span_id`, `trace_flags`; propagate W3C `traceparent` and `baggage` end to end. +- **Tenant & workload**: `tenant`, `workload` (service name), `region`, `env` (dev/stage/prod), `version` (git sha or semver). +- **Subject**: `component` (module), `operation` (verb/name), `resource` (purl/uri/subject id when safe). +- **Timing**: UTC ISO-8601 `timestamp`; durations in milliseconds with integers. +- **Outcome**: `status` (`ok|error|fault|throttle`), `error.code` (machine), `error.message` (human, redacted), `retryable` (bool). + +## Scrubbing policy +- Denylist PII/secrets before emit: emails, tokens, Authorization headers, bearer fragments, private keys, passwords, session IDs. +- Redact fields to `"[redacted]"` and add `redaction.reason` (`secret|pii|tenant_policy`). +- Hash low-cardinality identifiers when needed (`sha256` lowercase hex) and mark `hashed=true`. +- Logs must not contain full request/response bodies; store hashes plus lengths. For NDJSON exports, allow hashes + selected headers only. + +## Sampling defaults +- **Traces**: 10% head sampling non-prod; 100% for `status=error|fault` and for spans tagged `audit=true`. Prod default 5% with the same error/audit boost. +- **Logs**: info logs rate-limited per component (default 100/s); warn/error never sampled. Structured JSON only. +- **Metrics**: never sampled; counters/gauges/histograms use deterministic bucket boundaries documented in component specs. + +## Redaction override procedure +- Overrides are rare and must be auditable. +- To allow a field temporarily, set `telemetry.redaction.overrides=` in service config with change-ticket id; emit `redaction.override=true` tag on affected spans/logs. +- Overrides expire automatically after `telemetry.redaction.override_ttl` (default 24h); services refuse to start with expired overrides. +- All overrides are logged to `telemetry.redaction.audit` channel with actor, ticket, fields, TTL. + +## Determinism & offline posture +- No external enrichers; all enrichment data must be preloaded bundles (e.g., service map, tenant metadata). +- Sorting for exports: by `timestamp`, then `workload`, then `operation`. +- Time always UTC; avoid locale-specific formats. + +## Validation checklist +- [ ] `traceparent` propagated and present on inbound/outbound. +- [ ] Required fields present (`tenant`, `workload`, `operation`, `status`). +- [ ] Scrubbing tests cover auth headers and bodies. +- [ ] Sampling knobs configurable via env vars with documented defaults. diff --git a/docs/observability/tracing.md b/docs/observability/tracing.md new file mode 100644 index 000000000..044b353c2 --- /dev/null +++ b/docs/observability/tracing.md @@ -0,0 +1,37 @@ +# Tracing Standards (DOCS-OBS-50-004) + +Last updated: 2025-11-25 (Docs Tasks Md.VI) + +## Goals +- Consistent distributed tracing across services (API, workers, CLI). +- Safe for offline/air-gapped deployments. +- Deterministic span data for replay/debug. + +## Context propagation +- Use W3C headers: `traceparent` (required), `baggage` (optional key/value pairs). +- Preserve incoming `trace_id` for all downstream calls; create child spans per operation. +- For async work (queues, cron), copy `traceparent` and `baggage` into the message envelope; new span links to the stored context using **links**, not a new parent. + +## Span conventions +- Names: `.` (e.g., `riskengine.simulate`, `notify.deliver`). +- Required attributes: `tenant`, `workload` (service), `env`, `region`, `version`, `operation`, `status`. +- HTTP spans: add `http.method`, `http.route`, `http.status_code`, `net.peer.name`, `net.peer.port`. +- DB spans: `db.system`, `db.name`, `db.operation`, `db.statement` (omit literals). +- Message spans: `messaging.system`, `messaging.destination`, `messaging.operation` (`send|receive|process`), `messaging.message_id`. +- Errors: set `status=error`, include `error.code`, redacted `error.message`, `retryable` (bool). + +## Sampling +- Default head sampling: 10% non-prod, 5% prod. +- Always sample spans with `status=error|fault` or `audit=true`. +- Allow override via env `Tracing__SampleRate` (0–1) per service; document in runbooks. + +## Offline/air-gap posture +- No external exporters; emit OTLP to local collector or file. +- Disable remote enrichment; rely on bundled service map. +- All timestamps UTC; span ids deterministic only in scope of traceparent (no GUID reuse). + +## Validation checklist +- [ ] `traceparent` forwarded on every inbound/outbound call. +- [ ] Required attributes present on spans. +- [ ] Error spans include codes and redacted messages. +- [ ] Sampling knobs documented in service config. diff --git a/docs/operations/notifier-runbook.md b/docs/operations/notifier-runbook.md new file mode 100644 index 000000000..9e26d3d6b --- /dev/null +++ b/docs/operations/notifier-runbook.md @@ -0,0 +1,58 @@ +# Notifier Runbook + +Last updated: 2025-11-25 (Docs Tasks Md.V · DOCS-NOTIFY-40-001) + +## Purpose +Operational steps to deploy, monitor, and recover the Notifications service (WebService + Worker). + +## Pre-flight +- Secrets stored in Authority: SMTP creds, Slack/Teams hooks, webhook HMAC keys. +- Outbound allowlist updated for target channels. +- Mongo and Redis reachable; health checks pass. +- Offline kit loaded: channel manifests, default templates, rule seeds. + +## Deploy +1. Apply Kubernetes manifests/Compose stack from `ops/notify/` with image digests pinned. +2. Set env: + - `Notify__Mongo__ConnectionString` + - `Notify__Redis__ConnectionString` + - `Notify__Authority__BaseUrl` + - `Notify__ChannelAllowlist` + - `ASPNETCORE_URLS=http://0.0.0.0:8080` +3. Warm caches: `POST /api/v1/notify/admin/warm` (loads rules/templates into memory) — optional. +4. Verify `GET /api/v1/notify/health` returns `ready=true`. + +## Monitor +- Metrics (Prometheus): + - `notify_delivery_attempts_total` by status/channel/tenant. + - `notify_escalation_stage_total` by policy/stage. + - `notify_rule_eval_seconds_bucket` for worker latency. +- Logs: structured JSON with `tenant`, `ruleId`, `deliveryId`, `channel`, `status`. +- Traces: span `notify.delivery` with linkage to originating event `traceparent` when provided. + +## Common operations +- **List stuck deliveries**: `GET /api/v1/notify/deliveries?status=failed&from=`. +- **Replay delivery**: `POST /api/v1/notify/deliveries/{id}:replay` (idempotent; only re-renders if inputs unchanged). +- **Pause a tenant**: set tenant state `paused=true` via admin API; worker stops sending but keeps evaluating for audit. +- **Rotate secrets**: update Authority secret, then `POST /api/v1/notify/channels/{id}:refresh-secret`. + +## Failure recovery +- Worker crash loop: check Redis connectivity, template compile errors; run `notify-worker --validate-only` using current config. +- Mongo outage: worker backs off with exponential retry; after recovery, replay via `:replay` or digests as needed. +- Channel outage (e.g., Slack 5xx): throttles + retry policy handle transient errors; for extended outages, disable channel or swap to backup policy. + +## Auditing +- Delivery ledger retains attempt hashes and signatures; export via `/deliveries?from=...&to=...&format=ndjson` for offline review. +- Ack events stored with actor, timestamp, source IP. + +## Determinism safeguards +- Rule snapshots are versioned per tenant; upgrades swap snapshots atomically. +- Template rendering uses deterministic helpers only; no live lookups. +- Time sources are UTC; quiet hours evaluated using tenant timezone from config. + +## On-call checklist +- [ ] Health endpoints green. +- [ ] Delivery failure rate < 0.5% over last hour. +- [ ] Escalation backlog empty or within SLO. +- [ ] Redis memory < 75% and Mongo primary healthy. +- [ ] Latest release notes applied and channels validated. diff --git a/docs/operations/orchestrator-runbook.md b/docs/operations/orchestrator-runbook.md new file mode 100644 index 000000000..47e88e476 --- /dev/null +++ b/docs/operations/orchestrator-runbook.md @@ -0,0 +1,39 @@ +# Orchestrator Runbook (DOCS-ORCH-34-003) + +Last updated: 2025-11-25 + +## Pre-flight +- Ensure Mongo and queue backend reachable; health at `/api/v1/orchestrator/admin/health` green. +- Verify tenant allowlist and scopes (`orchestrator:*`) configured in Authority. +- Plugin bundles present and signatures verified. + +## Common operations +- **Start a run**: `POST /api/v1/orchestrator/runs` or `stella orch run start ...`. +- **Cancel a run**: `POST /runs/{runId}:cancel`; best-effort, idempotent. +- **Stream status**: WebSocket `/runs/stream` or CLI `stella orch run stream`. +- **Export ledger**: NDJSON export by time window for audits. + +## Incident response +- **Queue backlog**: Check queue depth; scale workers or pause schedulers; drain oldest first. Verify no stuck plugin. +- **Repeated failures**: Inspect run ledger for `error.code`; compare `inputsHash` and plugin version; roll back DAG version if regression. +- **Plugin auth errors**: rotate `secretRef` in Authority; warm worker cache; re-run impacted DAGs. +- **Scheduler runaway**: disable offending DAG version; clear scheduled triggers; confirm queue drains. + +## Health checks +- `GET /admin/health` — liveness/readiness + queue depth. +- Metrics: `orchestrator_runs_total`, `orchestrator_queue_depth`, `orchestrator_step_retries_total`, `orchestrator_run_duration_seconds`. +- Logs: structured JSON with `tenant`, `dagId`, `runId`, `status`; check for redaction markers. + +## Determinism/immutability +- Runs are append-only; do not mutate ledger entries. Use new DAG versions for fixes. +- Idempotency via `runToken`; reruns should reuse the same token when repeating intended work. + +## Offline/air-gap +- Keep plugin bundles and DAG specs in sealed storage; no remote fetch. +- Export logs/metrics/traces as NDJSON for offline analysis; include manifest/hash. + +## Quick checks +- [ ] Health green, queue depth normal. +- [ ] Latest plugin bundle signatures valid. +- [ ] No secrets in logs (spot-check redaction). +- [ ] Error budget within SLO (see `docs/observability/metrics-and-slos.md`). diff --git a/docs/orchestrator/api.md b/docs/orchestrator/api.md new file mode 100644 index 000000000..657cf3e75 --- /dev/null +++ b/docs/orchestrator/api.md @@ -0,0 +1,44 @@ +# Orchestrator API (DOCS-ORCH-33-001) + +> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied. + +Last updated: 2025-11-25 + +## Scope & headers +- Base path: `/api/v1/orchestrator`. +- Required headers: `Authorization: Bearer `, `X-Stella-Tenant`, `traceparent` (recommended), `Idempotency-Key` for POSTs that mutate state. +- Error envelope: see `docs/api/overview.md` (code/message/trace_id). + +## DAG management +- `POST /dags` — create/publish DAG version. Body includes `dagId`, `version`, `steps[]`, `edges[]`, `metadata`, `signature`. +- `GET /dags` — list DAGs (stable sort by `dagId`, then `version` DESC). Filters: `dagId`, `active=true|false`. +- `GET /dags/{dagId}/{version}` — fetch DAG definition. +- `POST /dags/{dagId}/{version}:disable` — disable a version (requires `orchestrator:admin`). + +## Runs +- `POST /runs` — start a run; accepts `dagId`, optional `version`, `inputs` (object), `runToken` (idempotency). Returns `runId`, `traceId`. +- `GET /runs` — list runs with filters `dagId`, `status`, `from`, `to`. Sort: `startedUtc` DESC, then `runId`. +- `GET /runs/{runId}` — run detail with step states and hashes. +- `POST /runs/{runId}:cancel` — request cancellation (best-effort, idempotent). + +## Steps & artifacts +- `GET /runs/{runId}/steps` — list step executions. +- `GET /runs/{runId}/steps/{stepId}` — step detail, including `attempts[]`, `logsRef`, `outputsHash`. +- `GET /artifacts/{hash}` — retrieve artifact by content hash (if tenant owns it). + +## WebSocket stream +- `GET /runs/stream?dagId=&status=` — server sends NDJSON events: `run.started`, `run.updated`, `step.updated`, `run.completed`, `run.failed`, `run.cancelled`. Fields: `tenant`, `dagId`, `runId`, `status`, `timestamp`, `traceId`. + +## Admin/ops +- `POST /admin/warm` — warm caches for DAGs/plugins (optional). +- `GET /admin/health` — liveness/readiness; includes queue depth per tenant. +- `GET /admin/metrics` — Prometheus scrape endpoint. + +## Determinism & offline posture +- All list endpoints have deterministic ordering; pagination via `page_token`/`page_size`. +- No remote fetches; DAGs/plugins must be preloaded. Exports available as NDJSON with stable ordering. +- Hashes lowercase hex; timestamps UTC ISO-8601. + +## Security +- Scopes: `orchestrator:read`, `orchestrator:write`, `orchestrator:admin` (publish/disable DAGs, cache warm). +- Tenant isolation enforced on every path; cross-tenant access forbidden. diff --git a/docs/orchestrator/architecture.md b/docs/orchestrator/architecture.md new file mode 100644 index 000000000..1bc03c412 --- /dev/null +++ b/docs/orchestrator/architecture.md @@ -0,0 +1,53 @@ +# Orchestrator Architecture (DOCS-ORCH-32-002) + +Last updated: 2025-11-25 + +## Runtime components +- **WebService**: REST + WebSocket API for DAG definitions, run status, and admin actions; issues idempotency tokens and enforces tenant isolation. +- **Scheduler**: timer/cron runner that instantiates DAG runs from schedules; publishes run intents into per-tenant queues. +- **Worker**: executes DAG steps; pulls from tenant queues, applies resource limits, and reports spans/metrics/logs. +- **Plugin host**: task plugins (HTTP call, queue dispatch, CLI tool, script) loaded from signed bundles; execution is sandboxed with deny-by-default network. + +## Data model +- **DAG**: directed acyclic graph with topological order; tie-break lexicographically by step id for determinism. +- **Run**: immutable record with `runId`, `dagVersion`, `tenant`, `inputsHash`, `status`, `traceId`, `startedUtc`, `endedUtc`. +- **Step execution**: each step captures `inputsHash`, `outputsHash`, `status`, `attempt`, `durationMs`, `logsRef`, `metricsRef`. + +## Execution flow +1) Client or scheduler creates a run (idempotent on `runToken`, `dagId`, `inputsHash`). +2) Scheduler enqueues run intent into tenant queue. +3) Worker dequeues, reconstructs DAG ordering, and executes steps: + - skip disabled steps; + - apply per-step concurrency, retries, and backoff; + - emit spans/metrics/logs with propagated `traceparent`. +4) Results are persisted append-only; WebSocket pushes status to clients. + +## Storage & queues +- Mongo stores DAG specs, versions, and run history (per-tenant collections or tenant key prefix). +- Queues: Redis/Mongo-backed FIFO per tenant; message includes `traceparent`, `runToken`, `dagVersion`, `inputsHash`. +- Artifacts (logs, outputs) referenced by content hash; stored in object storage or Mongo GridFS; hashes recorded in run record. + +## Security & AOC alignment +- Mandatory `X-Stella-Tenant`; cross-tenant DAGs prohibited. +- Scopes: `orchestrator:read|write|admin`; admin needed for DAG publish/delete. +- AOC: Orchestrator only schedules/executes; no policy/severity decisions. Inputs/outputs immutable; runs replayable. +- Sandboxing: per-step CPU/memory limits; network egress blocked unless step declares allowlist entry. + +## Determinism +- Step ordering: topological + lexical tie-breaks. +- Idempotency: `runToken` + `inputsHash`; retries reuse same `traceId`; outputs hashed (lowercase hex). +- Timestamps UTC; NDJSON exports sorted by `(startedUtc, dagId, runId)`. + +## Offline posture +- DAG specs and plugins shipped in signed offline bundles; no remote fetch. +- Transparency: export runs/logs/metrics/traces as NDJSON for air-gapped audit. + +## Observability +- Traces: spans named `orchestrator.run`, `orchestrator.step` with attributes `tenant`, `dagId`, `runId`, `stepId`, `status`. +- Metrics: `orchestrator_runs_total{tenant,status}`, `orchestrator_run_duration_seconds`, `orchestrator_queue_depth`, `orchestrator_step_retries_total`. +- Logs: structured JSON, redacted, carrying `trace_id`, `tenant`, `dagId`, `runId`, `stepId`. + +## Governance & rollout +- DAG publishing requires signature/owner metadata; versions immutable after publish. +- Rollback: schedule new version and disable old; runs stay immutable. +- Upgrade path: workers hot-reload plugins from bundle catalog; scheduler is stateless. diff --git a/docs/orchestrator/cli.md b/docs/orchestrator/cli.md new file mode 100644 index 000000000..690e304e2 --- /dev/null +++ b/docs/orchestrator/cli.md @@ -0,0 +1,35 @@ +# Orchestrator CLI (DOCS-ORCH-33-003) + +> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied. + +Last updated: 2025-11-25 + +## Commands +- `stella orch dag list` — list DAGs (stable order by `dagId`, `version` DESC). Flags: `--dag-id`, `--active`. +- `stella orch dag publish --file dag.yaml --signature sig.dsse` — publish DAG version (idempotent on signature). +- `stella orch dag disable --dag-id --version ` — disable version. +- `stella orch run start --dag-id [--version ] --inputs inputs.json [--run-token ]` — start run. +- `stella orch run list [--dag-id ] [--status running|completed|failed|cancelled] [--from ISO] [--to ISO]` — list runs. +- `stella orch run cancel --run-id ` — request cancellation. +- `stella orch run logs --run-id [--step-id ]` — fetch logs/artifacts (tenant scoped). +- `stella orch run stream --dag-id ` — stream NDJSON run events (matches WebSocket feed). + +## Global flags +- `--tenant ` (required), `--api-url`, `--token`, `--traceparent`, `--output json|table`, `--page-size`, `--page-token`. + +## Determinism & offline +- CLI sorts client-side exactly as API returns; table output uses fixed column order. +- Works offline against local WebService; no external downloads. +- All timestamps printed UTC; hashes lower-case hex. + +## Exit codes +- `0` success; `1` validation/HTTP error; `2` auth/tenant missing; `3` cancellation rejected. + +## Examples +```bash +# Start a run with idempotency token +stella orch run start --dag-id policy-refresh --inputs inputs.json --run-token 3e2b3d2e-1f21-4c2d-9a9d-123456789abc --tenant acme + +# Stream run updates +stella orch run stream --dag-id policy-refresh --tenant acme --output json +``` diff --git a/docs/orchestrator/console.md b/docs/orchestrator/console.md new file mode 100644 index 000000000..f75d2333e --- /dev/null +++ b/docs/orchestrator/console.md @@ -0,0 +1,33 @@ +# Orchestrator Console (DOCS-ORCH-33-002) + +> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied. + +Last updated: 2025-11-25 + +## Views +- **Run list**: deterministic table sorted by `startedUtc` DESC then `runId`; filters by `dagId`, `status`, `owner`, `time range`. +- **Run detail**: step graph with topological order; shows status, attempts, duration, logs link, outputs hash. +- **DAG catalog**: shows published versions with signatures and enable/disable state. +- **Queue health**: per-tenant queue depth/age, retry counts, worker availability. + +## Actions +- Start run (select DAG/version, supply inputs JSON, optional run token). +- Cancel run (best-effort). +- Download artifacts/logs (tenant-scoped). +- Stream live updates (WebSocket) for selected DAGs/runs. + +## Accessibility & UX +- Keyboard shortcuts: `f` focus filter, `r` refresh, `s` start run dialog. +- All timestamps UTC; durations shown with tooltip raw ms. +- Color palette meets WCAG AA; status badges have icons + text. +- Loading states deterministic; no infinite spinners—show “No data” with retry. + +## Determinism & offline +- Client-side sorting mirrors API order; pagination uses stable `page_token`. +- Console operates against local WebService; no external CDNs; fonts bundled. +- Exports (runs, steps) available as NDJSON for air-gapped audits. + +## Safety +- Tenant enforced via session; cross-tenant DAGs hidden. +- No raw secrets displayed; logs redacted server-side. +- Run cancellation confirms and records rationale for audit. diff --git a/docs/orchestrator/overview.md b/docs/orchestrator/overview.md new file mode 100644 index 000000000..a2635bc1e --- /dev/null +++ b/docs/orchestrator/overview.md @@ -0,0 +1,46 @@ +# Orchestrator Overview (DOCS-ORCH-32-001) + +> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied. + +Last updated: 2025-11-25 + +## Mission & value +- Coordinate deterministic job execution across StellaOps services (Policy, RiskEngine, VEX Lens, Export Center, Notify). +- Provide reproducible DAG runs with tenant isolation, auditability, and Aggregation-Only Contract (AOC) alignment. +- Stay sovereign/offline: all runners operate from bundled manifests and local queues; no external control plane. + +## Runtime shape +- **Services**: Orchestrator WebService (API/UI), Worker (executors), Scheduler (timer-based triggers). +- **Queues**: per-tenant work queues; FIFO with deterministic ordering and idempotency keys. +- **State**: Mongo for run metadata and DAG definitions; optional Redis for locks/throttles; all scoped by tenant. +- **APIs**: REST + WebSocket for run status/stream; admin endpoints require `orchestrator:admin` plus tenant header. + +## AOC alignment +- Orchestrator never derives policy/verdicts; it only executes declared DAG steps and records outcomes. +- Inputs/outputs are append-only; runs are immutable with replay tokens. +- No consensus logic; all decisions remain in owning services (Policy Engine, RiskEngine, etc.). + +## Determinism +- Stable DAG evaluation order (topological with lexical tie-breaks). +- Idempotency via run tokens and step hashes; retries preserve `trace_id`. +- UTC timestamps; hashes lowercase hex; NDJSON exports ordered by `(timestamp, dagId, runId)`. + +## Observability +- Traces propagate `traceparent`/`baggage` through scheduler→worker→task. +- Metrics: `orchestrator_runs_total{tenant,status}`, `orchestrator_run_duration_seconds`, `orchestrator_queue_depth`. +- Logs: structured JSON, redacted, tagged with `tenant`, `dagId`, `runId`, `status`. + +## Roles & responsibilities +- **Operator**: manage DAG definitions, quotas, tenant allowlists, SLOs. +- **Developer**: defines DAG specs and task plugins; supplies offline bundles for execution. +- **Security**: validates scopes, enforces AOC boundaries, reviews audit trails. + +## Offline posture +- DAG specs and plugins shipped in offline bundles; runners load from local disk. +- No outbound network during execution unless task explicitly declares an allowlisted endpoint. +- Transparency: export run logs/traces/metrics as NDJSON for air-gapped review. + +## Safety & governance +- Mandatory tenant header; cross-tenant DAGs forbidden. +- Step sandboxing: resource limits per task; deny network by default. +- Audit: every run records actor, tenant, DAG version, inputs hash, outputs hash, and rationale notes. diff --git a/docs/orchestrator/run-ledger.md b/docs/orchestrator/run-ledger.md new file mode 100644 index 000000000..1cd2b6af8 --- /dev/null +++ b/docs/orchestrator/run-ledger.md @@ -0,0 +1,36 @@ +# Orchestrator Run Ledger (DOCS-ORCH-34-001) + +> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied. + +Last updated: 2025-11-25 + +## Purpose +Immutable record of every DAG run and step execution for audit, replay, and offline export. + +## Record schema (conceptual) +- `tenant`, `runId`, `dagId`, `dagVersion`, `runToken`, `traceId` +- `status` (`running|completed|failed|cancelled`) +- `inputsHash`, `outputsHash` (overall) +- `startedUtc`, `endedUtc`, `durationMs` +- `steps[]`: + - `stepId`, `status`, `attempt`, `startedUtc`, `endedUtc`, `durationMs` + - `inputsHash`, `outputsHash`, `logsRef`, `metricsRef`, `errorCode`, `retryable` +- `events[]` (optional): ordered list of significant events with `timestamp`, `type`, `message`, `actor` + +## Storage +- Mongo collection partitioned by tenant; indexes on `(tenant, dagId, runId)`, `(tenant, status, startedUtc)`. +- Artifacts/logs referenced by content hash; stored separately (object storage/GridFS). +- Append-only updates; run status transitions are monotonic. + +## Exports +- NDJSON export sorted by `startedUtc`, then `runId`; includes steps/events inline. +- Exports include manifest with hash and count for determinism. + +## Observability +- Metrics derived from ledger: run counts, durations, failure rates, retry counts. +- Trace links preserved via stored `traceId`. + +## Governance +- Runs never mutated or deleted; cancellation recorded as an event. +- Access is tenant-scoped; admin queries require `orchestrator:admin`. +- Replay tokens can be derived from `inputsHash` + `dagVersion`; consumers must log rationale when replaying. diff --git a/docs/policy/effective-severity.md b/docs/policy/effective-severity.md new file mode 100644 index 000000000..e6b6f664b --- /dev/null +++ b/docs/policy/effective-severity.md @@ -0,0 +1,56 @@ +# Effective Severity Selection + +Last updated: 2025-11-25 (Docs Tasks Md.V) + +## Goal +Provide a deterministic, explainable way to pick the *effective* severity for a vulnerability or VEX observation when multiple signals exist (CVSS, KEV, exploit intel, VEX status, asset criticality, policy overrides). + +## Inputs +- **Base scores**: CVSS v3/v4 (base + temporal) and ecosystem-native severities (npm/yarn, PyPI, Maven). Missing scores are treated as `null`. +- **Exploitability**: KEV flag, EPSS probability, in-the-wild sightings, vendor exploit flags. +- **VEX status**: `not_affected`, `affected`, `fixed`, `under_investigation`, `unknown` (per OpenVEX/CSAF/CycloneDX-VEX). +- **Context signals**: asset criticality, exposure surface (`internet`, `intranet`, `airgap`), runtime enablement flag, workload type. +- **Policy overrides**: tenant/org rules (allow lists, waiver ids, force-upgrade requirements, SLA class). + +## Algorithm (deterministic) +1) **Normalize** all scores to a 0–10 float with 3-decimal rounding; store provenance for each signal. +2) **VEX gate** + - `not_affected` → effective severity `None` (score 0). Short-circuit unless override `force_evaluate=true`. + - `fixed` → keep score but add mitigation note. +3) **Exploit boost**: if `KEV=true` or `EPSS >= 0.7`, set `exploit_boost = +1.0` (cap at 10). Record reason. +4) **Exposure clamp** + - `airgap` → max score 7.0 unless override `allow_airgap_breakglass`. + - `intranet` → no cap; `internet` → no cap. +5) **Criticality weight**: multiply by asset criticality weight (default 1.0; high=1.2, medium=1.0, low=0.8). Clamp 0–10. +6) **Policy override**: apply explicit tenant rules (force severity, waive to `None`, or constrain max). Overrides always log the applied rule id. +7) **Bucket** into severity bands (stable mapping): + +| Score range (inclusive) | Band | +| --- | --- | +| 9.0–10.0 | Critical | +| 7.0–8.9 | High | +| 4.0–6.9 | Medium | +| 0.1–3.9 | Low | +| 0 | None | + +All arithmetic uses `decimal` and rounds only when persisted or returned (3 decimals) to stay replayable. + +## Examples +- CVSS 7.5 + KEV + internet + high criticality → base 7.5 → +1.0 exploit → *before clamp* 8.5 → ×1.2 = 10.2 → clamp 10.0 → **Critical**. +- CVSS 5.0, `not_affected` VEX → short-circuit to **None** (score 0) with rationale `vex:not_affected`. +- No CVSS, EPSS 0.2, exposure `airgap` → default score 0, band **None**; remains deterministic. + +## Observability +- Emit `stellaops.policy.effective_severity` histogram (0–10) with tags `tenant`, `source`, `vex_status`, `kev`, `epss_bucket`, `criticality`, `override_id`. +- Log structured event `severity.selected` containing input signals, applied steps, final score/band. +- Traces: span attribute `severity.score` and `severity.band`; link to upstream ingest span (`traceparent` propagated). + +## Determinism & Offline posture +- No live network lookups during evaluation; KEV/EPSS/VEX feeds must be preloaded from frozen bundles. +- Sorting of tied severities: break ties by subject id (lexicographic) then source priority (`vex` > `kev` > `cvss` > `ecosystem`). +- All timestamps are UTC ISO-8601; caches keyed by `(tenant, subject, advisory)`. + +## Contract for consumers +- API and CLI MUST return both the raw inputs and the chosen band/score so auditors can replay decisions. +- Downstream UIs should surface the rationale chain (steps 2–6) and any overrides applied. +- Waivers must reference the override id that changed the severity. diff --git a/docs/schemas/artifacts.md b/docs/schemas/artifacts.md new file mode 100644 index 000000000..7e65ac38b --- /dev/null +++ b/docs/schemas/artifacts.md @@ -0,0 +1,49 @@ +# Artifacts Schema (DOCS-ORCH-34-004) + +Last updated: 2025-11-25 + +## Purpose +Describe artifact kinds produced by Orchestrator runs and how they are stored, hashed, and referenced. + +## Artifact kinds +- **log**: NDJSON log fragment for a step/run. +- **metrics**: Prometheus/OpenMetrics snapshot for a step/run. +- **output**: arbitrary task output (JSON, NDJSON, binary), content-addressed. +- **manifest**: bundle manifest listing artifacts and hashes. + +## Schema (common fields) +```json +{ + "kind": "log|metrics|output|manifest", + "tenant": "acme", + "dagId": "string", + "runId": "string", + "stepId": "string", + "contentType": "application/json", + "hash": "sha256:", + "size": 1234, + "createdUtc": "2025-11-25T00:00:00Z", + "traceId": "optional", + "encryption": "none|aes256-gcm", + "compression": "none|gzip" +} +``` + +## Storage rules +- Content-addressed by `sha256` (lowercase hex). Filenames may use ``; metadata kept in Mongo with tenant scoping. +- Immutable; new versions create new hashes. +- Optional encryption: AES-256-GCM with keys from Authority `secretRef`; never store keys alongside artifacts. +- Compression optional (gzip) but hash is computed on compressed bytes; record `compression`. + +## Access & security +- Tenant-scoped reads; artifacts cannot be shared across tenants. +- No secrets stored; redact before writing. Logs/metrics already redacted at source. +- Access control enforced via orchestrator scopes; audit log every download/export. + +## Offline posture +- Artifacts may be exported as tarball with manifest (`manifest` kind) that lists hash, size, compression/encryption flags. +- Imports verify manifest hash and per-artifact hash before accepting. + +## Determinism +- Hash and size recorded at creation; manifests sorted by `kind`, then `dagId`, `runId`, `stepId`, `hash`. +- Timestamps UTC ISO-8601; NDJSON ordering stable. diff --git a/docs/security/aoc-invariants.md b/docs/security/aoc-invariants.md new file mode 100644 index 000000000..12ae81421 --- /dev/null +++ b/docs/security/aoc-invariants.md @@ -0,0 +1,29 @@ +# Aggregation-Only Contract (AOC) Invariants + +Last updated: 2025-11-25 (DOCS-ATTEST-75-002) + +## Core invariants (all components) +- **Tenant isolation**: Every API call requires `X-Stella-Tenant`; storage and caches are keyed by tenant. +- **Append-only inputs**: Evidence, advisories, and attestations are stored immutably; no in-place edits. +- **Determinism**: Sorting and pagination are stable; timestamps are UTC ISO-8601; hashes are lowercase hex. +- **No consensus**: Components enforce validation/verification only; no severity or policy decisions inside AOC services. +- **Offline-first**: All external data (feeds, keys, checkpoints) must be supplied via bundled inputs; no live fetches when sealed. + +## Attestor-specific invariants +- **Trust roots**: Verification keys are loaded exclusively from the bundled trust store; network key discovery is disabled in sealed mode. +- **DSSE only**: Inputs must be DSSE envelopes; detached signatures are rejected with a deterministic error code. +- **Transparency optional, explicit**: If a mirrored checkpoint is provided, inclusion proof is validated; otherwise results record `transparency=skipped` without failing the request. +- **Rationale trail**: Each verification emits a rationale list (e.g., `key.match`, `transparency.included`, `transparency.skipped`) so results are replayable. +- **Immutability**: Verified statements and rationale are recorded append-only in the delivery/verification ledger; retries must not overwrite prior entries. + +## Guardrails for implementers +- Never permit unsigned or partially signed payloads to proceed past parsing. +- Reject any outbound HTTP/S fetch during verification when `Attestor__Offline__Enabled=true`. +- Keep secret material out of logs; log statement digests and key ids only. +- Round numeric scores/weights only at the presentation boundary; internal math stays high-precision. + +## Audit checklist +- [ ] Tenant header enforced on every endpoint. +- [ ] Trust bundle hash matches the signed manifest on disk. +- [ ] Transparency verification results are captured per request. +- [ ] Ledger entries are append-only and carry rationale + trace ids. diff --git a/docs/security/notifications-hardening.md b/docs/security/notifications-hardening.md new file mode 100644 index 000000000..ae4d6f96c --- /dev/null +++ b/docs/security/notifications-hardening.md @@ -0,0 +1,37 @@ +# Notifications Hardening Guide + +Last updated: 2025-11-25 (Docs Tasks Md.V · DOCS-NOTIFY-40-001) + +## Threat model +- Tenant data isolation breaches (cross-tenant deliveries). +- Channel compromise (webhook leaks, OAuth token theft). +- Message tampering or replay. +- Flooding / notification storms. + +## Controls +- **Tenant isolation**: every rule/channel/template includes `tenant`; APIs enforce `X-Stella-Tenant`. Mongo collections are filtered by tenant with indexes on `(tenant, id)`. +- **Secrets**: channels reference Authority `secretRef`; secrets never stored in Notify DB. Rotate via Authority and `:refresh-secret`. +- **Outbound allowlist**: restrict hosts/ports per tenant; defaults block public internet in air-gapped kits. +- **Signing**: webhook deliveries include `X-Stella-Signature` HMAC-SHA256 over body+nonce; receivers must reject stale timestamps (>5m) and verify signature. +- **Replay protection**: delivery ledger de-dupes on `(channel, bodyHash)` for 24h; escalation tokens are single-use DSSE-signed. +- **Rate limits/throttles**: per-rule and per-channel throttles; quiet hours for non-critical traffic. +- **Templates sandboxed**: no file/network access; helpers are pure and deterministic. +- **Logging/PII**: payloads redacted based on rule labels; logs avoid full body, store hashes instead. +- **Audit**: all admin actions (create/update/delete channel or rule) logged with actor, trace id, and diff. + +## Deployment checklist +- [ ] Authority scopes `notify.viewer|operator|admin` configured; service accounts least-privilege. +- [ ] HTTPS everywhere; TLS 1.2+; HSTS on WebService front-door. +- [ ] Redis protected by auth and network policy; Mongo TLS + auth enabled. +- [ ] Outbound allowlists defined per environment; no wildcard `*`. +- [ ] Webhook receivers validate signatures and enforce host/IP allowlists. + +## Incident playbook (channel compromise) +1) Disable affected channel via `PATCH /channels/{id}` (`enabled=false`). +2) Rotate secret in Authority; refresh channel secret. +3) Search ledger for deliveries to compromised endpoint and notify tenants if required. +4) Re-enable with new endpoint/secret after validation. + +## Offline/air-gap notes +- Ship channel manifests and secrets via sealed bundles; keep hash manifest with signed checksum. +- Disable any channel type not supported in the enclave (e.g., external Slack) and use in-app or file-drop channels instead. diff --git a/docs/security/secrets-handling.md b/docs/security/secrets-handling.md new file mode 100644 index 000000000..cfc4f15aa --- /dev/null +++ b/docs/security/secrets-handling.md @@ -0,0 +1,20 @@ +# Secrets Handling (Orchestrator additions) + +Last updated: 2025-11-25 + +## Principles +- Secrets are stored in Authority and referenced via `secretRef`; services never persist raw secrets. +- No secrets in logs, traces, metrics, crash dumps, or health endpoints. +- Offline/air-gap: secrets are delivered through sealed bundles and loaded at startup only. + +## Orchestrator-specific rules (DOCS-ORCH-34-002) +- Plugin steps receive secrets via `secretRef`; workers fetch at step start and keep in-memory only for the step scope. +- Secrets are not written to the run ledger, artifacts, or NDJSON exports; only `secretRef` identifiers may appear. +- Network egress is deny-by-default; allowlists must reference `secretRef`-protected credentials when needed. +- Cancellation and retries must not log or surface secret material; redaction applies to all error paths. + +## Audit checklist +- [ ] Every plugin configuration uses `secretRef`, not inline values. +- [ ] Logs/traces verified to contain no secret payloads (redaction tests). +- [ ] Run ledger verified to store hashes/refs only. +- [ ] Secret refresh/rotation tested (Authority + worker reload). diff --git a/docs/slo/orchestrator-slo.md b/docs/slo/orchestrator-slo.md new file mode 100644 index 000000000..a1c3b6941 --- /dev/null +++ b/docs/slo/orchestrator-slo.md @@ -0,0 +1,30 @@ +# Orchestrator SLOs (DOCS-ORCH-34-005) + +Last updated: 2025-11-25 + +## Service level objectives +- **Availability**: 99.9% monthly for WebService API per tenant. +- **Run completion**: P95 run duration < 5m for standard DAGs; failure rate <1% over 30d. +- **Queue health**: backlog < 1000 items per tenant for >95% of 5m windows. +- **Event delivery**: WebSocket/stream delivery success > 99.5% (per day). + +## Error budget policy +- Window: 28 days. Burn alerts: + - 2× burn: page on-call. + - 14× burn: immediate mitigation (disable offending DAGs, scale workers). + +## Alerts (examples) +- Availability: `probe_success{job="orchestrator-api"} < 0.999 over 1h`. +- Latency: `histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le,route)) > 0.5`. +- Run failures: `rate(orchestrator_runs_total{status="failed"}[30m]) / rate(orchestrator_runs_total[30m]) > 0.01`. +- Queue backlog: `orchestrator_queue_depth > 1000` for 10m. + +## Dashboards +- Golden signals per service (traffic, errors, latency, saturation). +- Run outcome panel: success/fail/cancel counts, retry counts. +- Queue panel: depth, age, worker consumption rate. +- Burn-rate panel tied to error budget. + +## Ownership & review +- SLOs owned by Orchestrator Guild; reviewed quarterly or when architecture changes. +- Changes must be reflected in runbook and alert rules; update manifests for offline/air-gap monitoring kits. diff --git a/helm/signals/values-signals.yaml b/helm/signals/values-signals.yaml new file mode 100644 index 000000000..2b6ae21d1 --- /dev/null +++ b/helm/signals/values-signals.yaml @@ -0,0 +1,35 @@ +image: + repository: stellaops/signals + tag: "local" + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 5088 + +env: + ASPNETCORE_URLS: "http://+:5088" + Signals__Mongo__ConnectionString: "mongodb://signals-mongo:27017/signals" + Signals__Mongo__Database: "signals" + Signals__Cache__ConnectionString: "signals-redis:6379" + Signals__Storage__RootPath: "/data/artifacts" + Signals__Authority__Enabled: "false" + Signals__OpenApi__Enabled: "true" + +persistence: + enabled: true + mountPath: /data/artifacts + size: 5Gi + storageClass: "" + +redis: + enabled: true + host: signals-redis + port: 6379 + +mongo: + enabled: true + connectionString: "mongodb://signals-mongo:27017/signals" + +ingress: + enabled: false diff --git a/ops/devops/README-space.md b/ops/devops/README-space.md new file mode 100644 index 000000000..752141f02 --- /dev/null +++ b/ops/devops/README-space.md @@ -0,0 +1,28 @@ +# Freeing Disk Space Quickly + +If PTY allocation or builds fail with “No space left on device”, try these steps (safe order): + +1) Remove build/test artefacts: +``` +DRY_RUN=1 scripts/devops/cleanup-workspace.sh # preview +SAFE_ONLY=0 scripts/devops/cleanup-workspace.sh # include bin/obj if needed +``` + +2) Prune Docker cache (if allowed): +``` +docker system prune -af +docker volume prune -f +``` + +3) Clear NuGet cache (local user): +``` +rm -rf ~/.nuget/packages +``` + +4) Remove old CI artefacts: +- `ops/devops/artifacts/` +- `ops/devops/ci-110-runner/artifacts/` +- `ops/devops/sealed-mode-ci/artifacts/` +- `out/` directories + +5) Re-run the blocked workflow. diff --git a/ops/devops/artifacts/ci-110/20251125T034529Z/trx/concelier-storage-jobstore.trx b/ops/devops/artifacts/ci-110/20251125T034529Z/trx/concelier-storage-jobstore.trx deleted file mode 100644 index 2569be740..000000000 --- a/ops/devops/artifacts/ci-110/20251125T034529Z/trx/concelier-storage-jobstore.trx +++ /dev/null @@ -1,266 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0-rc.2.25502.107) -[xUnit.net 00:00:00.24] Discovering: StellaOps.Concelier.Storage.Mongo.Tests -[xUnit.net 00:00:00.30] Discovered: StellaOps.Concelier.Storage.Mongo.Tests -[xUnit.net 00:00:00.31] Starting: StellaOps.Concelier.Storage.Mongo.Tests -{"t":{"$date":"2025-11-25T03:46:58.044+00:00"},"s":"I", "c":"CONTROL", "id":23285, "ctx":"main","msg":"Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'"} -{"t":{"$date":"2025-11-25T03:46:58.047+00:00"},"s":"W", "c":"ASIO", "id":22601, "ctx":"main","msg":"No TransportLayer configured during NetworkInterface startup"} -{"t":{"$date":"2025-11-25T03:46:58.047+00:00"},"s":"I", "c":"NETWORK", "id":4648601, "ctx":"main","msg":"Implicit TCP FastOpen unavailable. If TCP FastOpen is required, set tcpFastOpenServer, tcpFastOpenClient, and tcpFastOpenQueueSize."} -{"t":{"$date":"2025-11-25T03:46:58.047+00:00"},"s":"W", "c":"ASIO", "id":22601, "ctx":"main","msg":"No TransportLayer configured during NetworkInterface startup"} -{"t":{"$date":"2025-11-25T03:46:58.048+00:00"},"s":"I", "c":"STORAGE", "id":4615611, "ctx":"initandlisten","msg":"MongoDB starting","attr":{"pid":149307,"port":34177,"dbPath":"/tmp/52ypckao.mi24085d8d097344d1d89ce_34177","architecture":"64-bit","host":"DESKTOP-7GHGC2M"}} -{"t":{"$date":"2025-11-25T03:46:58.048+00:00"},"s":"I", "c":"CONTROL", "id":23403, "ctx":"initandlisten","msg":"Build Info","attr":{"buildInfo":{"version":"4.4.4","gitVersion":"8db30a63db1a9d84bdcad0c83369623f708e0397","openSSLVersion":"OpenSSL 1.1.1w 11 Sep 2023","modules":[],"allocator":"tcmalloc","environment":{"distmod":"ubuntu2004","distarch":"x86_64","target_arch":"x86_64"}}}} -{"t":{"$date":"2025-11-25T03:46:58.048+00:00"},"s":"I", "c":"CONTROL", "id":51765, "ctx":"initandlisten","msg":"Operating System","attr":{"os":{"name":"Ubuntu","version":"24.04"}}} -{"t":{"$date":"2025-11-25T03:46:58.048+00:00"},"s":"I", "c":"CONTROL", "id":21951, "ctx":"initandlisten","msg":"Options set by command line","attr":{"options":{"net":{"bindIp":"127.0.0.1","port":34177},"replication":{"replSet":"singleNodeReplSet"},"storage":{"dbPath":"/tmp/52ypckao.mi24085d8d097344d1d89ce_34177"}}}} -{"t":{"$date":"2025-11-25T03:46:58.050+00:00"},"s":"I", "c":"STORAGE", "id":22297, "ctx":"initandlisten","msg":"Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem","tags":["startupWarnings"]} -{"t":{"$date":"2025-11-25T03:46:58.051+00:00"},"s":"I", "c":"STORAGE", "id":22315, "ctx":"initandlisten","msg":"Opening WiredTiger","attr":{"config":"create,cache_size=7485M,session_max=33000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000,close_scan_interval=10,close_handle_minimum=250),statistics_log=(wait=0),verbose=[recovery_progress,checkpoint_progress,compact_progress],"}} -{"t":{"$date":"2025-11-25T03:46:58.505+00:00"},"s":"I", "c":"STORAGE", "id":22430, "ctx":"initandlisten","msg":"WiredTiger message","attr":{"message":"[1764042418:505803][149307:0x7c5deb73fcc0], txn-recover: [WT_VERB_RECOVERY | WT_VERB_RECOVERY_PROGRESS] Set global recovery timestamp: (0, 0)"}} -{"t":{"$date":"2025-11-25T03:46:58.505+00:00"},"s":"I", "c":"STORAGE", "id":22430, "ctx":"initandlisten","msg":"WiredTiger message","attr":{"message":"[1764042418:505867][149307:0x7c5deb73fcc0], txn-recover: [WT_VERB_RECOVERY | WT_VERB_RECOVERY_PROGRESS] Set global oldest timestamp: (0, 0)"}} -{"t":{"$date":"2025-11-25T03:46:58.518+00:00"},"s":"I", "c":"STORAGE", "id":4795906, "ctx":"initandlisten","msg":"WiredTiger opened","attr":{"durationMillis":467}} -{"t":{"$date":"2025-11-25T03:46:58.518+00:00"},"s":"I", "c":"RECOVERY", "id":23987, "ctx":"initandlisten","msg":"WiredTiger recoveryTimestamp","attr":{"recoveryTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:46:58.541+00:00"},"s":"I", "c":"STORAGE", "id":4366408, "ctx":"initandlisten","msg":"No table logging settings modifications are required for existing WiredTiger tables","attr":{"loggingEnabled":false}} -{"t":{"$date":"2025-11-25T03:46:58.541+00:00"},"s":"I", "c":"STORAGE", "id":22262, "ctx":"initandlisten","msg":"Timestamp monitor starting"} -{"t":{"$date":"2025-11-25T03:46:58.549+00:00"},"s":"W", "c":"CONTROL", "id":22120, "ctx":"initandlisten","msg":"Access control is not enabled for the database. Read and write access to data and configuration is unrestricted","tags":["startupWarnings"]} -{"t":{"$date":"2025-11-25T03:46:58.550+00:00"},"s":"I", "c":"STORAGE", "id":20536, "ctx":"initandlisten","msg":"Flow Control is enabled on this deployment"} -{"t":{"$date":"2025-11-25T03:46:58.552+00:00"},"s":"I", "c":"SHARDING", "id":20997, "ctx":"initandlisten","msg":"Refreshed RWC defaults","attr":{"newDefaults":{}}} -{"t":{"$date":"2025-11-25T03:46:58.552+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.startup_log","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"703631ce-8f0d-4a10-bbb7-9d5bf9ef670d"}},"options":{"capped":true,"size":10485760}}} -{"t":{"$date":"2025-11-25T03:46:58.570+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.startup_log","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:46:58.571+00:00"},"s":"I", "c":"FTDC", "id":20625, "ctx":"initandlisten","msg":"Initializing full-time diagnostic data capture","attr":{"dataDirectory":"/tmp/52ypckao.mi24085d8d097344d1d89ce_34177/diagnostic.data"}} -{"t":{"$date":"2025-11-25T03:46:58.573+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.replset.oplogTruncateAfterPoint","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"cdf2e71f-d90e-4aea-9d8f-0c44a436e8e5"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:46:58.592+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.replset.oplogTruncateAfterPoint","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:46:58.592+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.replset.minvalid","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"e280bf8e-917b-4655-a7ee-c02bce23629f"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:46:58.612+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.replset.minvalid","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:46:58.612+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.replset.election","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"e437541a-6cff-4c82-89b8-8a63ae74ccd1"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:46:58.630+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.replset.election","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:46:58.630+00:00"},"s":"I", "c":"REPL", "id":21311, "ctx":"initandlisten","msg":"Did not find local initialized voted for document at startup"} -{"t":{"$date":"2025-11-25T03:46:58.630+00:00"},"s":"I", "c":"REPL", "id":21312, "ctx":"initandlisten","msg":"Did not find local Rollback ID document at startup. Creating one"} -{"t":{"$date":"2025-11-25T03:46:58.630+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.system.rollback.id","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"4d719115-1783-4038-acf6-b047f74c33a1"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:46:58.650+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.system.rollback.id","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:46:58.650+00:00"},"s":"I", "c":"REPL", "id":21531, "ctx":"initandlisten","msg":"Initialized the rollback ID","attr":{"rbid":1}} -{"t":{"$date":"2025-11-25T03:46:58.650+00:00"},"s":"I", "c":"REPL", "id":21313, "ctx":"initandlisten","msg":"Did not find local replica set configuration document at startup","attr":{"error":{"code":47,"codeName":"NoMatchingDocument","errmsg":"Did not find replica set configuration document in local.system.replset"}}} -{"t":{"$date":"2025-11-25T03:46:58.652+00:00"},"s":"I", "c":"CONTROL", "id":20714, "ctx":"LogicalSessionCacheRefresh","msg":"Failed to refresh session cache, will try again at the next refresh interval","attr":{"error":"NotYetInitialized: Replication has not yet been configured"}} -{"t":{"$date":"2025-11-25T03:46:58.652+00:00"},"s":"I", "c":"CONTROL", "id":20712, "ctx":"LogicalSessionCacheReap","msg":"Sessions collection is not set up; waiting until next sessions reap interval","attr":{"error":"NamespaceNotFound: config.system.sessions does not exist"}} -{"t":{"$date":"2025-11-25T03:46:58.652+00:00"},"s":"I", "c":"REPL", "id":40440, "ctx":"initandlisten","msg":"Starting the TopologyVersionObserver"} -{"t":{"$date":"2025-11-25T03:46:58.653+00:00"},"s":"I", "c":"REPL", "id":40445, "ctx":"TopologyVersionObserver","msg":"Started TopologyVersionObserver"} -{"t":{"$date":"2025-11-25T03:46:58.653+00:00"},"s":"I", "c":"NETWORK", "id":23015, "ctx":"listener","msg":"Listening on","attr":{"address":"/tmp/mongodb-34177.sock"}} -{"t":{"$date":"2025-11-25T03:46:58.653+00:00"},"s":"I", "c":"NETWORK", "id":23015, "ctx":"listener","msg":"Listening on","attr":{"address":"127.0.0.1"}} -{"t":{"$date":"2025-11-25T03:46:58.653+00:00"},"s":"I", "c":"NETWORK", "id":23016, "ctx":"listener","msg":"Waiting for connections","attr":{"port":34177,"ssl":"off"}} -{"t":{"$date":"2025-11-25T03:46:59.029+00:00"},"s":"I", "c":"NETWORK", "id":22943, "ctx":"listener","msg":"Connection accepted","attr":{"remote":"127.0.0.1:41390","connectionId":1,"connectionCount":1}} -{"t":{"$date":"2025-11-25T03:46:59.052+00:00"},"s":"I", "c":"NETWORK", "id":51800, "ctx":"conn1","msg":"client metadata","attr":{"remote":"127.0.0.1:41390","client":"conn1","doc":{"driver":{"name":"mongo-csharp-driver","version":"3.5.0"},"os":{"type":"Linux","name":"Ubuntu 24.04.3 LTS","architecture":"x86_64","version":"24.04.3"},"platform":".NET 10.0.0-rc.2.25502.107"}}} -{"t":{"$date":"2025-11-25T03:46:59.102+00:00"},"s":"I", "c":"NETWORK", "id":22943, "ctx":"listener","msg":"Connection accepted","attr":{"remote":"127.0.0.1:41392","connectionId":2,"connectionCount":2}} -{"t":{"$date":"2025-11-25T03:46:59.104+00:00"},"s":"I", "c":"NETWORK", "id":51800, "ctx":"conn2","msg":"client metadata","attr":{"remote":"127.0.0.1:41392","client":"conn2","doc":{"driver":{"name":"mongo-csharp-driver","version":"3.5.0"},"os":{"type":"Linux","name":"Ubuntu 24.04.3 LTS","architecture":"x86_64","version":"24.04.3"},"platform":".NET 10.0.0-rc.2.25502.107"}}} -{"t":{"$date":"2025-11-25T03:46:59.110+00:00"},"s":"I", "c":"NETWORK", "id":22943, "ctx":"listener","msg":"Connection accepted","attr":{"remote":"127.0.0.1:41398","connectionId":3,"connectionCount":3}} -{"t":{"$date":"2025-11-25T03:46:59.110+00:00"},"s":"I", "c":"NETWORK", "id":51800, "ctx":"conn3","msg":"client metadata","attr":{"remote":"127.0.0.1:41398","client":"conn3","doc":{"driver":{"name":"mongo-csharp-driver","version":"3.5.0"},"os":{"type":"Linux","name":"Ubuntu 24.04.3 LTS","architecture":"x86_64","version":"24.04.3"},"platform":".NET 10.0.0-rc.2.25502.107"}}} -{"t":{"$date":"2025-11-25T03:46:59.124+00:00"},"s":"I", "c":"REPL", "id":21356, "ctx":"conn3","msg":"replSetInitiate admin command received from client"} -{"t":{"$date":"2025-11-25T03:46:59.124+00:00"},"s":"I", "c":"REPL", "id":21357, "ctx":"conn3","msg":"replSetInitiate config object parses ok","attr":{"numMembers":1}} -{"t":{"$date":"2025-11-25T03:46:59.124+00:00"},"s":"I", "c":"REPL", "id":21251, "ctx":"conn3","msg":"Creating replication oplog","attr":{"oplogSizeMB":48102}} -{"t":{"$date":"2025-11-25T03:46:59.124+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn3","msg":"createCollection","attr":{"namespace":"local.oplog.rs","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"053aabcf-9a69-46cd-a015-04790a28df83"}},"options":{"capped":true,"size":50439009894.0,"autoIndexId":false}}} -{"t":{"$date":"2025-11-25T03:46:59.140+00:00"},"s":"I", "c":"STORAGE", "id":22383, "ctx":"conn3","msg":"The size storer reports that the oplog contains","attr":{"numRecords":0,"dataSize":0}} -{"t":{"$date":"2025-11-25T03:46:59.140+00:00"},"s":"I", "c":"STORAGE", "id":22382, "ctx":"conn3","msg":"WiredTiger record store oplog processing finished","attr":{"durationMillis":0}} -{"t":{"$date":"2025-11-25T03:46:59.182+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn3","msg":"createCollection","attr":{"namespace":"local.system.replset","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"17fcea78-1e4a-45c3-b642-f84a5ed5e94a"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:46:59.199+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"conn3","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.system.replset","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042419,"i":1}}}} -{"t":{"$date":"2025-11-25T03:46:59.200+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn3","msg":"createCollection","attr":{"namespace":"admin.system.version","uuidDisposition":"provided","uuid":{"uuid":{"$uuid":"ed811933-0189-4439-9d54-39e00e9db918"}},"options":{"uuid":{"$uuid":"ed811933-0189-4439-9d54-39e00e9db918"}}}} -{"t":{"$date":"2025-11-25T03:46:59.222+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"conn3","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"admin.system.version","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042419,"i":1}}}} -{"t":{"$date":"2025-11-25T03:46:59.222+00:00"},"s":"I", "c":"COMMAND", "id":20459, "ctx":"conn3","msg":"Setting featureCompatibilityVersion","attr":{"newVersion":"4.4"}} -{"t":{"$date":"2025-11-25T03:46:59.222+00:00"},"s":"I", "c":"NETWORK", "id":22991, "ctx":"conn3","msg":"Skip closing connection for connection","attr":{"connectionId":3}} -{"t":{"$date":"2025-11-25T03:46:59.222+00:00"},"s":"I", "c":"NETWORK", "id":22991, "ctx":"conn3","msg":"Skip closing connection for connection","attr":{"connectionId":2}} -{"t":{"$date":"2025-11-25T03:46:59.222+00:00"},"s":"I", "c":"NETWORK", "id":22991, "ctx":"conn3","msg":"Skip closing connection for connection","attr":{"connectionId":1}} -{"t":{"$date":"2025-11-25T03:46:59.223+00:00"},"s":"I", "c":"REPL", "id":21392, "ctx":"conn3","msg":"New replica set config in use","attr":{"config":{"_id":"singleNodeReplSet","version":1,"term":0,"protocolVersion":1,"writeConcernMajorityJournalDefault":true,"members":[{"_id":0,"host":"127.0.0.1:34177","arbiterOnly":false,"buildIndexes":true,"hidden":false,"priority":1.0,"tags":{},"slaveDelay":0,"votes":1}],"settings":{"chainingAllowed":true,"heartbeatIntervalMillis":2000,"heartbeatTimeoutSecs":10,"electionTimeoutMillis":10000,"catchUpTimeoutMillis":-1,"catchUpTakeoverDelayMillis":30000,"getLastErrorModes":{},"getLastErrorDefaults":{"w":1,"wtimeout":0},"replicaSetId":{"$oid":"692526b3e401d61632b17dbe"}}}}} -{"t":{"$date":"2025-11-25T03:46:59.223+00:00"},"s":"I", "c":"REPL", "id":21393, "ctx":"conn3","msg":"Found self in config","attr":{"hostAndPort":"127.0.0.1:34177"}} -{"t":{"$date":"2025-11-25T03:46:59.223+00:00"},"s":"I", "c":"REPL", "id":21358, "ctx":"conn3","msg":"Replica set state transition","attr":{"newState":"STARTUP2","oldState":"STARTUP"}} -{"t":{"$date":"2025-11-25T03:46:59.223+00:00"},"s":"I", "c":"REPL", "id":21306, "ctx":"conn3","msg":"Starting replication storage threads"} -{"t":{"$date":"2025-11-25T03:46:59.228+00:00"},"s":"I", "c":"REPL", "id":21358, "ctx":"conn3","msg":"Replica set state transition","attr":{"newState":"RECOVERING","oldState":"STARTUP2"}} -{"t":{"$date":"2025-11-25T03:46:59.228+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn3","msg":"createCollection","attr":{"namespace":"local.replset.initialSyncId","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"ea9b840a-3f2f-495e-9503-e90226f4437e"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:46:59.248+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"conn3","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.replset.initialSyncId","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042419,"i":1}}}} -{"t":{"$date":"2025-11-25T03:46:59.248+00:00"},"s":"I", "c":"REPL", "id":21299, "ctx":"conn3","msg":"Starting replication fetcher thread"} -{"t":{"$date":"2025-11-25T03:46:59.248+00:00"},"s":"I", "c":"REPL", "id":21300, "ctx":"conn3","msg":"Starting replication applier thread"} -{"t":{"$date":"2025-11-25T03:46:59.248+00:00"},"s":"I", "c":"REPL", "id":21301, "ctx":"conn3","msg":"Starting replication reporter thread"} -{"t":{"$date":"2025-11-25T03:46:59.248+00:00"},"s":"I", "c":"COMMAND", "id":51803, "ctx":"conn3","msg":"Slow query","attr":{"type":"command","ns":"local.system.replset","command":{"replSetInitiate":{"_id":"singleNodeReplSet","members":[{"_id":0,"host":"127.0.0.1:34177"}]},"$db":"admin","lsid":{"id":{"$uuid":"28798271-3e18-48d9-8e83-e22f1566379f"}}},"numYields":0,"reslen":163,"locks":{"ParallelBatchWriterMode":{"acquireCount":{"r":18}},"ReplicationStateTransition":{"acquireCount":{"w":19}},"Global":{"acquireCount":{"r":11,"w":6,"W":2}},"Database":{"acquireCount":{"r":10,"w":4,"W":2}},"Collection":{"acquireCount":{"r":3,"w":5}},"Mutex":{"acquireCount":{"r":17}},"oplog":{"acquireCount":{"w":1}}},"flowControl":{"acquireCount":5,"timeAcquiringMicros":3},"storage":{},"protocol":"op_msg","durationMillis":124}} -{"t":{"$date":"2025-11-25T03:46:59.249+00:00"},"s":"I", "c":"REPL", "id":21224, "ctx":"OplogApplier-0","msg":"Starting oplog application"} -{"t":{"$date":"2025-11-25T03:46:59.249+00:00"},"s":"I", "c":"REPL", "id":21358, "ctx":"OplogApplier-0","msg":"Replica set state transition","attr":{"newState":"SECONDARY","oldState":"RECOVERING"}} -{"t":{"$date":"2025-11-25T03:46:59.249+00:00"},"s":"I", "c":"ELECTION", "id":4615652, "ctx":"OplogApplier-0","msg":"Starting an election, since we've seen no PRIMARY in election timeout period","attr":{"electionTimeoutPeriodMillis":10000}} -{"t":{"$date":"2025-11-25T03:46:59.249+00:00"},"s":"I", "c":"ELECTION", "id":21438, "ctx":"OplogApplier-0","msg":"Conducting a dry run election to see if we could be elected","attr":{"currentTerm":0}} -{"t":{"$date":"2025-11-25T03:46:59.249+00:00"},"s":"I", "c":"ELECTION", "id":21444, "ctx":"ReplCoord-0","msg":"Dry election run succeeded, running for election","attr":{"newTerm":1}} -{"t":{"$date":"2025-11-25T03:46:59.251+00:00"},"s":"I", "c":"ELECTION", "id":21450, "ctx":"ReplCoord-2","msg":"Election succeeded, assuming primary role","attr":{"term":1}} -{"t":{"$date":"2025-11-25T03:46:59.251+00:00"},"s":"I", "c":"REPL", "id":21358, "ctx":"ReplCoord-2","msg":"Replica set state transition","attr":{"newState":"PRIMARY","oldState":"SECONDARY"}} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21106, "ctx":"ReplCoord-2","msg":"Resetting sync source to empty","attr":{"previousSyncSource":":27017"}} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21359, "ctx":"ReplCoord-2","msg":"Entering primary catch-up mode"} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21363, "ctx":"ReplCoord-2","msg":"Exited primary catch-up mode"} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21107, "ctx":"ReplCoord-2","msg":"Stopping replication producer"} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21239, "ctx":"ReplBatcher","msg":"Oplog buffer has been drained","attr":{"term":1}} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21239, "ctx":"ReplBatcher","msg":"Oplog buffer has been drained","attr":{"term":1}} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21343, "ctx":"RstlKillOpThread","msg":"Starting to kill user operations"} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21344, "ctx":"RstlKillOpThread","msg":"Stopped killing user operations"} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21340, "ctx":"RstlKillOpThread","msg":"State transition ops metrics","attr":{"metrics":{"lastStateTransition":"stepUp","userOpsKilled":0,"userOpsRunning":1}}} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":4508103, "ctx":"OplogApplier-0","msg":"Increment the config term via reconfig"} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":21353, "ctx":"OplogApplier-0","msg":"replSetReconfig config object parses ok","attr":{"numMembers":1}} -{"t":{"$date":"2025-11-25T03:46:59.252+00:00"},"s":"I", "c":"REPL", "id":51814, "ctx":"OplogApplier-0","msg":"Persisting new config to disk"} -{"t":{"$date":"2025-11-25T03:46:59.254+00:00"},"s":"I", "c":"REPL", "id":21392, "ctx":"OplogApplier-0","msg":"New replica set config in use","attr":{"config":{"_id":"singleNodeReplSet","version":1,"term":1,"protocolVersion":1,"writeConcernMajorityJournalDefault":true,"members":[{"_id":0,"host":"127.0.0.1:34177","arbiterOnly":false,"buildIndexes":true,"hidden":false,"priority":1.0,"tags":{},"slaveDelay":0,"votes":1}],"settings":{"chainingAllowed":true,"heartbeatIntervalMillis":2000,"heartbeatTimeoutSecs":10,"electionTimeoutMillis":10000,"catchUpTimeoutMillis":-1,"catchUpTakeoverDelayMillis":30000,"getLastErrorModes":{},"getLastErrorDefaults":{"w":1,"wtimeout":0},"replicaSetId":{"$oid":"692526b3e401d61632b17dbe"}}}}} -{"t":{"$date":"2025-11-25T03:46:59.254+00:00"},"s":"I", "c":"REPL", "id":21393, "ctx":"OplogApplier-0","msg":"Found self in config","attr":{"hostAndPort":"127.0.0.1:34177"}} -{"t":{"$date":"2025-11-25T03:46:59.254+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"OplogApplier-0","msg":"createCollection","attr":{"namespace":"config.transactions","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"68aef30f-d014-4d85-8569-834e53e1b940"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:46:59.289+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"OplogApplier-0","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"config.transactions","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042419,"i":3}}}} -{"t":{"$date":"2025-11-25T03:46:59.289+00:00"},"s":"I", "c":"STORAGE", "id":20657, "ctx":"OplogApplier-0","msg":"IndexBuildsCoordinator::onStepUp - this node is stepping up to primary"} -{"t":{"$date":"2025-11-25T03:46:59.289+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"OplogApplier-0","msg":"createCollection","attr":{"namespace":"config.system.indexBuilds","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"cec9aa75-1b94-4923-b5b0-50485fd3bb9b"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:46:59.305+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"OplogApplier-0","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"config.system.indexBuilds","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042419,"i":5}}}} -{"t":{"$date":"2025-11-25T03:46:59.306+00:00"},"s":"I", "c":"REPL", "id":21331, "ctx":"OplogApplier-0","msg":"Transition to primary complete; database writes are now permitted"} -{"t":{"$date":"2025-11-25T03:46:59.306+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"monitoring-keys-for-HMAC","msg":"createCollection","attr":{"namespace":"admin.system.keys","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"d2b8a5fd-68bc-4768-95de-0a76f2fa698d"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:46:59.327+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"monitoring-keys-for-HMAC","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"admin.system.keys","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042419,"i":6}}}} -{"t":{"$date":"2025-11-25T03:46:59.329+00:00"},"s":"I", "c":"STORAGE", "id":22310, "ctx":"WTJournalFlusher","msg":"Triggering the first stable checkpoint","attr":{"initialData":{"$timestamp":{"t":1764042419,"i":1}},"prevStable":{"$timestamp":{"t":0,"i":0}},"currStable":{"$timestamp":{"t":1764042419,"i":7}}}} -{"t":{"$date":"2025-11-25T03:46:59.472+00:00"},"s":"I", "c":"CONTROL", "id":23285, "ctx":"main","msg":"Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'"} -{"t":{"$date":"2025-11-25T03:46:59.477+00:00"},"s":"W", "c":"ASIO", "id":22601, "ctx":"main","msg":"No TransportLayer configured during NetworkInterface startup"} -{"t":{"$date":"2025-11-25T03:46:59.477+00:00"},"s":"I", "c":"NETWORK", "id":4648601, "ctx":"main","msg":"Implicit TCP FastOpen unavailable. If TCP FastOpen is required, set tcpFastOpenServer, tcpFastOpenClient, and tcpFastOpenQueueSize."} -{"t":{"$date":"2025-11-25T03:46:59.477+00:00"},"s":"W", "c":"ASIO", "id":22601, "ctx":"main","msg":"No TransportLayer configured during NetworkInterface startup"} -{"t":{"$date":"2025-11-25T03:46:59.478+00:00"},"s":"I", "c":"STORAGE", "id":4615611, "ctx":"initandlisten","msg":"MongoDB starting","attr":{"pid":149392,"port":32865,"dbPath":"/tmp/f54m2zn5.l0x0520d32fc74c4f838929_32865","architecture":"64-bit","host":"DESKTOP-7GHGC2M"}} -{"t":{"$date":"2025-11-25T03:46:59.478+00:00"},"s":"I", "c":"CONTROL", "id":23403, "ctx":"initandlisten","msg":"Build Info","attr":{"buildInfo":{"version":"4.4.4","gitVersion":"8db30a63db1a9d84bdcad0c83369623f708e0397","openSSLVersion":"OpenSSL 1.1.1w 11 Sep 2023","modules":[],"allocator":"tcmalloc","environment":{"distmod":"ubuntu2004","distarch":"x86_64","target_arch":"x86_64"}}}} -{"t":{"$date":"2025-11-25T03:46:59.478+00:00"},"s":"I", "c":"CONTROL", "id":51765, "ctx":"initandlisten","msg":"Operating System","attr":{"os":{"name":"Ubuntu","version":"24.04"}}} -{"t":{"$date":"2025-11-25T03:46:59.478+00:00"},"s":"I", "c":"CONTROL", "id":21951, "ctx":"initandlisten","msg":"Options set by command line","attr":{"options":{"net":{"bindIp":"127.0.0.1","port":32865},"replication":{"replSet":"singleNodeReplSet"},"storage":{"dbPath":"/tmp/f54m2zn5.l0x0520d32fc74c4f838929_32865"}}}} -{"t":{"$date":"2025-11-25T03:46:59.479+00:00"},"s":"I", "c":"STORAGE", "id":22297, "ctx":"initandlisten","msg":"Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem","tags":["startupWarnings"]} -{"t":{"$date":"2025-11-25T03:46:59.480+00:00"},"s":"I", "c":"STORAGE", "id":22315, "ctx":"initandlisten","msg":"Opening WiredTiger","attr":{"config":"create,cache_size=7485M,session_max=33000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000,close_scan_interval=10,close_handle_minimum=250),statistics_log=(wait=0),verbose=[recovery_progress,checkpoint_progress,compact_progress],"}} -{"t":{"$date":"2025-11-25T03:46:59.946+00:00"},"s":"I", "c":"STORAGE", "id":22430, "ctx":"initandlisten","msg":"WiredTiger message","attr":{"message":"[1764042419:946594][149392:0x710e8d06fcc0], txn-recover: [WT_VERB_RECOVERY | WT_VERB_RECOVERY_PROGRESS] Set global recovery timestamp: (0, 0)"}} -{"t":{"$date":"2025-11-25T03:46:59.946+00:00"},"s":"I", "c":"STORAGE", "id":22430, "ctx":"initandlisten","msg":"WiredTiger message","attr":{"message":"[1764042419:946648][149392:0x710e8d06fcc0], txn-recover: [WT_VERB_RECOVERY | WT_VERB_RECOVERY_PROGRESS] Set global oldest timestamp: (0, 0)"}} -{"t":{"$date":"2025-11-25T03:46:59.959+00:00"},"s":"I", "c":"STORAGE", "id":4795906, "ctx":"initandlisten","msg":"WiredTiger opened","attr":{"durationMillis":479}} -{"t":{"$date":"2025-11-25T03:46:59.959+00:00"},"s":"I", "c":"RECOVERY", "id":23987, "ctx":"initandlisten","msg":"WiredTiger recoveryTimestamp","attr":{"recoveryTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:46:59.982+00:00"},"s":"I", "c":"STORAGE", "id":4366408, "ctx":"initandlisten","msg":"No table logging settings modifications are required for existing WiredTiger tables","attr":{"loggingEnabled":false}} -{"t":{"$date":"2025-11-25T03:46:59.982+00:00"},"s":"I", "c":"STORAGE", "id":22262, "ctx":"initandlisten","msg":"Timestamp monitor starting"} -{"t":{"$date":"2025-11-25T03:46:59.995+00:00"},"s":"W", "c":"CONTROL", "id":22120, "ctx":"initandlisten","msg":"Access control is not enabled for the database. Read and write access to data and configuration is unrestricted","tags":["startupWarnings"]} -{"t":{"$date":"2025-11-25T03:46:59.996+00:00"},"s":"I", "c":"STORAGE", "id":20536, "ctx":"initandlisten","msg":"Flow Control is enabled on this deployment"} -{"t":{"$date":"2025-11-25T03:46:59.997+00:00"},"s":"I", "c":"SHARDING", "id":20997, "ctx":"initandlisten","msg":"Refreshed RWC defaults","attr":{"newDefaults":{}}} -{"t":{"$date":"2025-11-25T03:46:59.997+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.startup_log","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"ad29fb35-58e2-4924-b4fb-17eeb34908cf"}},"options":{"capped":true,"size":10485760}}} -{"t":{"$date":"2025-11-25T03:47:00.021+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.startup_log","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:47:00.022+00:00"},"s":"I", "c":"FTDC", "id":20625, "ctx":"initandlisten","msg":"Initializing full-time diagnostic data capture","attr":{"dataDirectory":"/tmp/f54m2zn5.l0x0520d32fc74c4f838929_32865/diagnostic.data"}} -{"t":{"$date":"2025-11-25T03:47:00.023+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.replset.oplogTruncateAfterPoint","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"6ebbbc40-875b-448f-ac4d-9c7fe238b5eb"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.044+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.replset.oplogTruncateAfterPoint","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:47:00.044+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.replset.minvalid","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"603415e4-8dc1-4e82-9f62-0e6d48de7352"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.061+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.replset.minvalid","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:47:00.062+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.replset.election","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"94ff23a8-11b3-423c-af02-2422e71f24fc"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.084+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.replset.election","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:47:00.085+00:00"},"s":"I", "c":"REPL", "id":21311, "ctx":"initandlisten","msg":"Did not find local initialized voted for document at startup"} -{"t":{"$date":"2025-11-25T03:47:00.085+00:00"},"s":"I", "c":"REPL", "id":21312, "ctx":"initandlisten","msg":"Did not find local Rollback ID document at startup. Creating one"} -{"t":{"$date":"2025-11-25T03:47:00.085+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"initandlisten","msg":"createCollection","attr":{"namespace":"local.system.rollback.id","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"a2f46637-91c1-4f52-8256-a20611926972"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.101+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"initandlisten","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.system.rollback.id","index":"_id_","commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:47:00.101+00:00"},"s":"I", "c":"REPL", "id":21531, "ctx":"initandlisten","msg":"Initialized the rollback ID","attr":{"rbid":1}} -{"t":{"$date":"2025-11-25T03:47:00.101+00:00"},"s":"I", "c":"REPL", "id":21313, "ctx":"initandlisten","msg":"Did not find local replica set configuration document at startup","attr":{"error":{"code":47,"codeName":"NoMatchingDocument","errmsg":"Did not find replica set configuration document in local.system.replset"}}} -{"t":{"$date":"2025-11-25T03:47:00.102+00:00"},"s":"I", "c":"CONTROL", "id":20714, "ctx":"LogicalSessionCacheRefresh","msg":"Failed to refresh session cache, will try again at the next refresh interval","attr":{"error":"NotYetInitialized: Replication has not yet been configured"}} -{"t":{"$date":"2025-11-25T03:47:00.103+00:00"},"s":"I", "c":"CONTROL", "id":20712, "ctx":"LogicalSessionCacheReap","msg":"Sessions collection is not set up; waiting until next sessions reap interval","attr":{"error":"NamespaceNotFound: config.system.sessions does not exist"}} -{"t":{"$date":"2025-11-25T03:47:00.103+00:00"},"s":"I", "c":"REPL", "id":40440, "ctx":"initandlisten","msg":"Starting the TopologyVersionObserver"} -{"t":{"$date":"2025-11-25T03:47:00.103+00:00"},"s":"I", "c":"REPL", "id":40445, "ctx":"TopologyVersionObserver","msg":"Started TopologyVersionObserver"} -{"t":{"$date":"2025-11-25T03:47:00.103+00:00"},"s":"I", "c":"NETWORK", "id":23015, "ctx":"listener","msg":"Listening on","attr":{"address":"/tmp/mongodb-32865.sock"}} -{"t":{"$date":"2025-11-25T03:47:00.103+00:00"},"s":"I", "c":"NETWORK", "id":23015, "ctx":"listener","msg":"Listening on","attr":{"address":"127.0.0.1"}} -{"t":{"$date":"2025-11-25T03:47:00.103+00:00"},"s":"I", "c":"NETWORK", "id":23016, "ctx":"listener","msg":"Waiting for connections","attr":{"port":32865,"ssl":"off"}} -{"t":{"$date":"2025-11-25T03:47:00.141+00:00"},"s":"I", "c":"NETWORK", "id":22943, "ctx":"listener","msg":"Connection accepted","attr":{"remote":"127.0.0.1:32952","connectionId":1,"connectionCount":1}} -{"t":{"$date":"2025-11-25T03:47:00.142+00:00"},"s":"I", "c":"NETWORK", "id":51800, "ctx":"conn1","msg":"client metadata","attr":{"remote":"127.0.0.1:32952","client":"conn1","doc":{"driver":{"name":"mongo-csharp-driver","version":"3.5.0"},"os":{"type":"Linux","name":"Ubuntu 24.04.3 LTS","architecture":"x86_64","version":"24.04.3"},"platform":".NET 10.0.0-rc.2.25502.107"}}} -{"t":{"$date":"2025-11-25T03:47:00.143+00:00"},"s":"I", "c":"NETWORK", "id":22943, "ctx":"listener","msg":"Connection accepted","attr":{"remote":"127.0.0.1:32956","connectionId":2,"connectionCount":2}} -{"t":{"$date":"2025-11-25T03:47:00.144+00:00"},"s":"I", "c":"NETWORK", "id":51800, "ctx":"conn2","msg":"client metadata","attr":{"remote":"127.0.0.1:32956","client":"conn2","doc":{"driver":{"name":"mongo-csharp-driver","version":"3.5.0"},"os":{"type":"Linux","name":"Ubuntu 24.04.3 LTS","architecture":"x86_64","version":"24.04.3"},"platform":".NET 10.0.0-rc.2.25502.107"}}} -{"t":{"$date":"2025-11-25T03:47:00.144+00:00"},"s":"I", "c":"NETWORK", "id":22943, "ctx":"listener","msg":"Connection accepted","attr":{"remote":"127.0.0.1:32958","connectionId":3,"connectionCount":3}} -{"t":{"$date":"2025-11-25T03:47:00.144+00:00"},"s":"I", "c":"NETWORK", "id":51800, "ctx":"conn3","msg":"client metadata","attr":{"remote":"127.0.0.1:32958","client":"conn3","doc":{"driver":{"name":"mongo-csharp-driver","version":"3.5.0"},"os":{"type":"Linux","name":"Ubuntu 24.04.3 LTS","architecture":"x86_64","version":"24.04.3"},"platform":".NET 10.0.0-rc.2.25502.107"}}} -{"t":{"$date":"2025-11-25T03:47:00.145+00:00"},"s":"I", "c":"REPL", "id":21356, "ctx":"conn2","msg":"replSetInitiate admin command received from client"} -{"t":{"$date":"2025-11-25T03:47:00.145+00:00"},"s":"I", "c":"REPL", "id":21357, "ctx":"conn2","msg":"replSetInitiate config object parses ok","attr":{"numMembers":1}} -{"t":{"$date":"2025-11-25T03:47:00.145+00:00"},"s":"I", "c":"REPL", "id":21251, "ctx":"conn2","msg":"Creating replication oplog","attr":{"oplogSizeMB":48087}} -{"t":{"$date":"2025-11-25T03:47:00.146+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn2","msg":"createCollection","attr":{"namespace":"local.oplog.rs","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"20717f8c-54ff-4b74-a452-ece55bdb7dbb"}},"options":{"capped":true,"size":50423249920.0,"autoIndexId":false}}} -{"t":{"$date":"2025-11-25T03:47:00.155+00:00"},"s":"I", "c":"STORAGE", "id":22383, "ctx":"conn2","msg":"The size storer reports that the oplog contains","attr":{"numRecords":0,"dataSize":0}} -{"t":{"$date":"2025-11-25T03:47:00.155+00:00"},"s":"I", "c":"STORAGE", "id":22382, "ctx":"conn2","msg":"WiredTiger record store oplog processing finished","attr":{"durationMillis":0}} -{"t":{"$date":"2025-11-25T03:47:00.200+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn2","msg":"createCollection","attr":{"namespace":"local.system.replset","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"e76a7051-11f0-41d1-9e22-39b73aa284c2"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.217+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"conn2","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.system.replset","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042420,"i":1}}}} -{"t":{"$date":"2025-11-25T03:47:00.218+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn2","msg":"createCollection","attr":{"namespace":"admin.system.version","uuidDisposition":"provided","uuid":{"uuid":{"$uuid":"7ca3ad6a-3e97-4f2c-aef9-b17fe9bd6c74"}},"options":{"uuid":{"$uuid":"7ca3ad6a-3e97-4f2c-aef9-b17fe9bd6c74"}}}} -{"t":{"$date":"2025-11-25T03:47:00.235+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"conn2","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"admin.system.version","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042420,"i":1}}}} -{"t":{"$date":"2025-11-25T03:47:00.235+00:00"},"s":"I", "c":"COMMAND", "id":20459, "ctx":"conn2","msg":"Setting featureCompatibilityVersion","attr":{"newVersion":"4.4"}} -{"t":{"$date":"2025-11-25T03:47:00.235+00:00"},"s":"I", "c":"NETWORK", "id":22991, "ctx":"conn2","msg":"Skip closing connection for connection","attr":{"connectionId":3}} -{"t":{"$date":"2025-11-25T03:47:00.235+00:00"},"s":"I", "c":"NETWORK", "id":22991, "ctx":"conn2","msg":"Skip closing connection for connection","attr":{"connectionId":2}} -{"t":{"$date":"2025-11-25T03:47:00.235+00:00"},"s":"I", "c":"NETWORK", "id":22991, "ctx":"conn2","msg":"Skip closing connection for connection","attr":{"connectionId":1}} -{"t":{"$date":"2025-11-25T03:47:00.235+00:00"},"s":"I", "c":"REPL", "id":21392, "ctx":"conn2","msg":"New replica set config in use","attr":{"config":{"_id":"singleNodeReplSet","version":1,"term":0,"protocolVersion":1,"writeConcernMajorityJournalDefault":true,"members":[{"_id":0,"host":"127.0.0.1:32865","arbiterOnly":false,"buildIndexes":true,"hidden":false,"priority":1.0,"tags":{},"slaveDelay":0,"votes":1}],"settings":{"chainingAllowed":true,"heartbeatIntervalMillis":2000,"heartbeatTimeoutSecs":10,"electionTimeoutMillis":10000,"catchUpTimeoutMillis":-1,"catchUpTakeoverDelayMillis":30000,"getLastErrorModes":{},"getLastErrorDefaults":{"w":1,"wtimeout":0},"replicaSetId":{"$oid":"692526b48d3d1985c4de93e4"}}}}} -{"t":{"$date":"2025-11-25T03:47:00.235+00:00"},"s":"I", "c":"REPL", "id":21393, "ctx":"conn2","msg":"Found self in config","attr":{"hostAndPort":"127.0.0.1:32865"}} -{"t":{"$date":"2025-11-25T03:47:00.235+00:00"},"s":"I", "c":"REPL", "id":21358, "ctx":"conn2","msg":"Replica set state transition","attr":{"newState":"STARTUP2","oldState":"STARTUP"}} -{"t":{"$date":"2025-11-25T03:47:00.235+00:00"},"s":"I", "c":"REPL", "id":21306, "ctx":"conn2","msg":"Starting replication storage threads"} -{"t":{"$date":"2025-11-25T03:47:00.238+00:00"},"s":"I", "c":"REPL", "id":21358, "ctx":"conn2","msg":"Replica set state transition","attr":{"newState":"RECOVERING","oldState":"STARTUP2"}} -{"t":{"$date":"2025-11-25T03:47:00.238+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn2","msg":"createCollection","attr":{"namespace":"local.replset.initialSyncId","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"1703a7f0-89fd-4541-b1f9-034025c93c97"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.260+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"conn2","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"local.replset.initialSyncId","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042420,"i":1}}}} -{"t":{"$date":"2025-11-25T03:47:00.260+00:00"},"s":"I", "c":"REPL", "id":21299, "ctx":"conn2","msg":"Starting replication fetcher thread"} -{"t":{"$date":"2025-11-25T03:47:00.260+00:00"},"s":"I", "c":"REPL", "id":21300, "ctx":"conn2","msg":"Starting replication applier thread"} -{"t":{"$date":"2025-11-25T03:47:00.261+00:00"},"s":"I", "c":"REPL", "id":21301, "ctx":"conn2","msg":"Starting replication reporter thread"} -{"t":{"$date":"2025-11-25T03:47:00.261+00:00"},"s":"I", "c":"REPL", "id":21224, "ctx":"OplogApplier-0","msg":"Starting oplog application"} -{"t":{"$date":"2025-11-25T03:47:00.261+00:00"},"s":"I", "c":"COMMAND", "id":51803, "ctx":"conn2","msg":"Slow query","attr":{"type":"command","ns":"local.system.replset","command":{"replSetInitiate":{"_id":"singleNodeReplSet","members":[{"_id":0,"host":"127.0.0.1:32865"}]},"$db":"admin","lsid":{"id":{"$uuid":"5884425c-dce7-4528-b599-e26f26b5dff1"}}},"numYields":0,"reslen":163,"locks":{"ParallelBatchWriterMode":{"acquireCount":{"r":18}},"ReplicationStateTransition":{"acquireCount":{"w":19}},"Global":{"acquireCount":{"r":11,"w":6,"W":2}},"Database":{"acquireCount":{"r":10,"w":4,"W":2}},"Collection":{"acquireCount":{"r":3,"w":5}},"Mutex":{"acquireCount":{"r":17}},"oplog":{"acquireCount":{"w":1}}},"flowControl":{"acquireCount":5,"timeAcquiringMicros":5},"storage":{},"protocol":"op_msg","durationMillis":115}} -{"t":{"$date":"2025-11-25T03:47:00.261+00:00"},"s":"I", "c":"REPL", "id":21358, "ctx":"OplogApplier-0","msg":"Replica set state transition","attr":{"newState":"SECONDARY","oldState":"RECOVERING"}} -{"t":{"$date":"2025-11-25T03:47:00.261+00:00"},"s":"I", "c":"ELECTION", "id":4615652, "ctx":"OplogApplier-0","msg":"Starting an election, since we've seen no PRIMARY in election timeout period","attr":{"electionTimeoutPeriodMillis":10000}} -{"t":{"$date":"2025-11-25T03:47:00.262+00:00"},"s":"I", "c":"ELECTION", "id":21438, "ctx":"OplogApplier-0","msg":"Conducting a dry run election to see if we could be elected","attr":{"currentTerm":0}} -{"t":{"$date":"2025-11-25T03:47:00.262+00:00"},"s":"I", "c":"ELECTION", "id":21444, "ctx":"ReplCoord-0","msg":"Dry election run succeeded, running for election","attr":{"newTerm":1}} -{"t":{"$date":"2025-11-25T03:47:00.264+00:00"},"s":"I", "c":"ELECTION", "id":21450, "ctx":"ReplCoord-0","msg":"Election succeeded, assuming primary role","attr":{"term":1}} -{"t":{"$date":"2025-11-25T03:47:00.264+00:00"},"s":"I", "c":"REPL", "id":21358, "ctx":"ReplCoord-0","msg":"Replica set state transition","attr":{"newState":"PRIMARY","oldState":"SECONDARY"}} -{"t":{"$date":"2025-11-25T03:47:00.264+00:00"},"s":"I", "c":"REPL", "id":21106, "ctx":"ReplCoord-0","msg":"Resetting sync source to empty","attr":{"previousSyncSource":":27017"}} -{"t":{"$date":"2025-11-25T03:47:00.264+00:00"},"s":"I", "c":"REPL", "id":21359, "ctx":"ReplCoord-0","msg":"Entering primary catch-up mode"} -{"t":{"$date":"2025-11-25T03:47:00.264+00:00"},"s":"I", "c":"REPL", "id":21363, "ctx":"ReplCoord-0","msg":"Exited primary catch-up mode"} -{"t":{"$date":"2025-11-25T03:47:00.264+00:00"},"s":"I", "c":"REPL", "id":21107, "ctx":"ReplCoord-0","msg":"Stopping replication producer"} -{"t":{"$date":"2025-11-25T03:47:00.265+00:00"},"s":"I", "c":"REPL", "id":21239, "ctx":"ReplBatcher","msg":"Oplog buffer has been drained","attr":{"term":1}} -{"t":{"$date":"2025-11-25T03:47:00.265+00:00"},"s":"I", "c":"REPL", "id":21343, "ctx":"RstlKillOpThread","msg":"Starting to kill user operations"} -{"t":{"$date":"2025-11-25T03:47:00.265+00:00"},"s":"I", "c":"REPL", "id":21344, "ctx":"RstlKillOpThread","msg":"Stopped killing user operations"} -{"t":{"$date":"2025-11-25T03:47:00.265+00:00"},"s":"I", "c":"REPL", "id":21340, "ctx":"RstlKillOpThread","msg":"State transition ops metrics","attr":{"metrics":{"lastStateTransition":"stepUp","userOpsKilled":0,"userOpsRunning":1}}} -{"t":{"$date":"2025-11-25T03:47:00.265+00:00"},"s":"I", "c":"REPL", "id":4508103, "ctx":"OplogApplier-0","msg":"Increment the config term via reconfig"} -{"t":{"$date":"2025-11-25T03:47:00.265+00:00"},"s":"I", "c":"REPL", "id":21353, "ctx":"OplogApplier-0","msg":"replSetReconfig config object parses ok","attr":{"numMembers":1}} -{"t":{"$date":"2025-11-25T03:47:00.265+00:00"},"s":"I", "c":"REPL", "id":51814, "ctx":"OplogApplier-0","msg":"Persisting new config to disk"} -{"t":{"$date":"2025-11-25T03:47:00.267+00:00"},"s":"I", "c":"REPL", "id":21392, "ctx":"OplogApplier-0","msg":"New replica set config in use","attr":{"config":{"_id":"singleNodeReplSet","version":1,"term":1,"protocolVersion":1,"writeConcernMajorityJournalDefault":true,"members":[{"_id":0,"host":"127.0.0.1:32865","arbiterOnly":false,"buildIndexes":true,"hidden":false,"priority":1.0,"tags":{},"slaveDelay":0,"votes":1}],"settings":{"chainingAllowed":true,"heartbeatIntervalMillis":2000,"heartbeatTimeoutSecs":10,"electionTimeoutMillis":10000,"catchUpTimeoutMillis":-1,"catchUpTakeoverDelayMillis":30000,"getLastErrorModes":{},"getLastErrorDefaults":{"w":1,"wtimeout":0},"replicaSetId":{"$oid":"692526b48d3d1985c4de93e4"}}}}} -{"t":{"$date":"2025-11-25T03:47:00.267+00:00"},"s":"I", "c":"REPL", "id":21393, "ctx":"OplogApplier-0","msg":"Found self in config","attr":{"hostAndPort":"127.0.0.1:32865"}} -{"t":{"$date":"2025-11-25T03:47:00.267+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"OplogApplier-0","msg":"createCollection","attr":{"namespace":"config.transactions","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"90401e83-c42b-4ce2-a5ad-49a4c81c816b"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.285+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"OplogApplier-0","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"config.transactions","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042420,"i":3}}}} -{"t":{"$date":"2025-11-25T03:47:00.286+00:00"},"s":"I", "c":"STORAGE", "id":20657, "ctx":"OplogApplier-0","msg":"IndexBuildsCoordinator::onStepUp - this node is stepping up to primary"} -{"t":{"$date":"2025-11-25T03:47:00.286+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"OplogApplier-0","msg":"createCollection","attr":{"namespace":"config.system.indexBuilds","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"e0a50b99-1d2c-4142-ae31-a78f724d5f96"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.303+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"OplogApplier-0","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"config.system.indexBuilds","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042420,"i":5}}}} -{"t":{"$date":"2025-11-25T03:47:00.303+00:00"},"s":"I", "c":"REPL", "id":21331, "ctx":"OplogApplier-0","msg":"Transition to primary complete; database writes are now permitted"} -{"t":{"$date":"2025-11-25T03:47:00.304+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"monitoring-keys-for-HMAC","msg":"createCollection","attr":{"namespace":"admin.system.keys","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"72c6ddd0-0840-4549-9145-58849a210856"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.322+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"monitoring-keys-for-HMAC","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"admin.system.keys","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042420,"i":6}}}} -{"t":{"$date":"2025-11-25T03:47:00.323+00:00"},"s":"I", "c":"STORAGE", "id":22310, "ctx":"WTJournalFlusher","msg":"Triggering the first stable checkpoint","attr":{"initialData":{"$timestamp":{"t":1764042420,"i":1}},"prevStable":{"$timestamp":{"t":0,"i":0}},"currStable":{"$timestamp":{"t":1764042420,"i":7}}}} -{"t":{"$date":"2025-11-25T03:47:00.580+00:00"},"s":"I", "c":"COMMAND", "id":518070, "ctx":"conn2","msg":"CMD: drop","attr":{"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs"}} -{"t":{"$date":"2025-11-25T03:47:00.762+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn2","msg":"createCollection","attr":{"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"a39564e0-a39c-47ce-b7f1-eb7e36a2686a"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:00.795+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"conn2","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042420,"i":9}}}} -{"t":{"$date":"2025-11-25T03:47:00.998+00:00"},"s":"I", "c":"COMMAND", "id":518070, "ctx":"conn2","msg":"CMD: drop","attr":{"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs"}} -{"t":{"$date":"2025-11-25T03:47:00.998+00:00"},"s":"I", "c":"STORAGE", "id":23879, "ctx":"conn2","msg":"About to abort all index builders","attr":{"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs","uuid":{"uuid":{"$uuid":"a39564e0-a39c-47ce-b7f1-eb7e36a2686a"}},"reason":"Collection concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs(a39564e0-a39c-47ce-b7f1-eb7e36a2686a) is being dropped"}} -{"t":{"$date":"2025-11-25T03:47:00.998+00:00"},"s":"I", "c":"STORAGE", "id":20314, "ctx":"conn2","msg":"dropCollection: storage engine will take ownership of drop-pending collection","attr":{"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs","uuid":{"uuid":{"$uuid":"a39564e0-a39c-47ce-b7f1-eb7e36a2686a"}},"dropOpTime":{"ts":{"$timestamp":{"t":0,"i":0}},"t":-1},"commitTimestamp":{"$timestamp":{"t":0,"i":0}}}} -{"t":{"$date":"2025-11-25T03:47:00.998+00:00"},"s":"I", "c":"STORAGE", "id":20318, "ctx":"conn2","msg":"Finishing collection drop","attr":{"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs","uuid":{"uuid":{"$uuid":"a39564e0-a39c-47ce-b7f1-eb7e36a2686a"}}}} -{"t":{"$date":"2025-11-25T03:47:00.998+00:00"},"s":"I", "c":"STORAGE", "id":22206, "ctx":"conn2","msg":"Deferring table drop for index","attr":{"index":"_id_","namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs","uuid":{"uuid":{"$uuid":"a39564e0-a39c-47ce-b7f1-eb7e36a2686a"}},"ident":"index-24-1032418473798039975","commitTimestamp":{"$timestamp":{"t":1764042420,"i":15}}}} -{"t":{"$date":"2025-11-25T03:47:00.998+00:00"},"s":"I", "c":"STORAGE", "id":22214, "ctx":"conn2","msg":"Deferring table drop for collection","attr":{"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs","ident":"collection-23-1032418473798039975","commitTimestamp":{"$timestamp":{"t":1764042420,"i":15}}}} -{"t":{"$date":"2025-11-25T03:47:01.013+00:00"},"s":"I", "c":"COMMAND", "id":518070, "ctx":"conn2","msg":"CMD: drop","attr":{"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs"}} -{"t":{"$date":"2025-11-25T03:47:01.018+00:00"},"s":"I", "c":"STORAGE", "id":20320, "ctx":"conn2","msg":"createCollection","attr":{"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs","uuidDisposition":"generated","uuid":{"uuid":{"$uuid":"169c4fe9-6a2c-4f20-92cb-ed7517b7d6a2"}},"options":{}}} -{"t":{"$date":"2025-11-25T03:47:01.037+00:00"},"s":"I", "c":"INDEX", "id":20345, "ctx":"conn2","msg":"Index build: done building","attr":{"buildUUID":null,"namespace":"concelier-tests-7e8484ac4f7a4ae08dd2c21f49c49720.jobs","index":"_id_","commitTimestamp":{"$timestamp":{"t":1764042421,"i":1}}}} -[xUnit.net 00:00:03.64] Finished: StellaOps.Concelier.Storage.Mongo.Tests - - - - - Data collector 'Blame' message: All tests finished running, Sequence file will not be generated. - - - - \ No newline at end of file diff --git a/ops/devops/artifacts/ci-110/20251125T040900Z/trx/concelier-web-orch.trx b/ops/devops/artifacts/ci-110/20251125T040900Z/trx/concelier-web-orch.trx index 2e8bf3434..4ca888afc 100644 --- a/ops/devops/artifacts/ci-110/20251125T040900Z/trx/concelier-web-orch.trx +++ b/ops/devops/artifacts/ci-110/20251125T040900Z/trx/concelier-web-orch.trx @@ -1,8 +1,8 @@  - - - - + + + + @@ -12,17 +12,17 @@ [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0-rc.2.25502.107) -[xUnit.net 00:00:00.25] Discovering: StellaOps.Concelier.WebService.Tests -[xUnit.net 00:00:00.31] Discovered: StellaOps.Concelier.WebService.Tests -[xUnit.net 00:00:00.31] Starting: StellaOps.Concelier.WebService.Tests -[xUnit.net 00:00:00.33] Finished: StellaOps.Concelier.WebService.Tests +[xUnit.net 00:00:00.26] Discovering: StellaOps.Concelier.WebService.Tests +[xUnit.net 00:00:00.33] Discovered: StellaOps.Concelier.WebService.Tests +[xUnit.net 00:00:00.34] Starting: StellaOps.Concelier.WebService.Tests +[xUnit.net 00:00:00.36] Finished: StellaOps.Concelier.WebService.Tests - - No test matches the given testcase filter `FullyQualifiedName~Orchestrator` in /mnt/e/dev/git.stella-ops.org/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/bin/Debug/net10.0/StellaOps.Concelier.WebService.Tests.dll + + No test matches the given testcase filter `ClassName~OrchestratorEndpointsTests` in /mnt/e/dev/git.stella-ops.org/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/bin/Debug/net10.0/StellaOps.Concelier.WebService.Tests.dll - + Data collector 'Blame' message: All tests finished running, Sequence file will not be generated. diff --git a/ops/devops/artifacts/ci-110/20251125T041800Z/trx/concelier-web-orch.trx b/ops/devops/artifacts/ci-110/20251125T041800Z/trx/concelier-web-orch.trx new file mode 100644 index 000000000..bd364e807 --- /dev/null +++ b/ops/devops/artifacts/ci-110/20251125T041800Z/trx/concelier-web-orch.trx @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0-rc.2.25502.107) +[xUnit.net 00:00:00.35] Discovering: StellaOps.Concelier.WebService.Tests +[xUnit.net 00:00:00.43] Discovered: StellaOps.Concelier.WebService.Tests +[xUnit.net 00:00:00.44] Starting: StellaOps.Concelier.WebService.Tests +[xUnit.net 00:00:00.46] Finished: StellaOps.Concelier.WebService.Tests + + + + + No test matches the given testcase filter `OrchestratorEndpointsTests` in /mnt/e/dev/git.stella-ops.org/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/bin/Debug/net10.0/StellaOps.Concelier.WebService.Tests.dll + + + Data collector 'Blame' message: All tests finished running, Sequence file will not be generated. + + + + \ No newline at end of file diff --git a/ops/devops/ci-110-runner/test-filters.md b/ops/devops/ci-110-runner/test-filters.md new file mode 100644 index 000000000..9a43f8529 --- /dev/null +++ b/ops/devops/ci-110-runner/test-filters.md @@ -0,0 +1,11 @@ +# CI-110 runner filters (Concelier/Excititor smoke) + +## Concelier +- WebService health: `HealthAndReadyEndpointsRespond` +- Storage.Mongo job store: `FullyQualifiedName~MongoJobStore` +- WebService orchestrator endpoints: TODO (tests not yet present; add to WebService.Tests then filter with `FullyQualifiedName~Orchestrator`) + +## Excititor +- WebService airgap import: `FullyQualifiedName~AirgapImportEndpointTests` + +Artifacts are written under `ops/devops/artifacts/ci-110//` by `run-ci-110.sh`. diff --git a/ops/devops/observability/grafana/policy-pipeline.json b/ops/devops/observability/grafana/policy-pipeline.json new file mode 100644 index 000000000..d29e3e2ad --- /dev/null +++ b/ops/devops/observability/grafana/policy-pipeline.json @@ -0,0 +1,78 @@ +{ + "schemaVersion": 39, + "title": "Policy Pipeline", + "panels": [ + { + "type": "stat", + "title": "Compile p99 (s)", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "s", "decimals": 2}}, + "targets": [ + {"expr": "histogram_quantile(0.99, sum(rate(policy_compile_duration_seconds_bucket[5m])) by (le))"} + ] + }, + { + "type": "timeseries", + "title": "Compile Duration (p95/p50)", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "s", "decimals": 2}}, + "targets": [ + {"expr": "histogram_quantile(0.95, sum(rate(policy_compile_duration_seconds_bucket[5m])) by (le))", "legendFormat": "p95"}, + {"expr": "histogram_quantile(0.50, sum(rate(policy_compile_duration_seconds_bucket[5m])) by (le))", "legendFormat": "p50"} + ] + }, + { + "type": "stat", + "title": "Simulation Queue Depth", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "none"}}, + "targets": [{"expr": "sum(policy_simulation_queue_depth)"}] + }, + { + "type": "timeseries", + "title": "Queue Depth by Stage", + "datasource": "Prometheus", + "targets": [{"expr": "policy_simulation_queue_depth", "legendFormat": "{{stage}}"}], + "fieldConfig": {"defaults": {"unit": "none"}} + }, + { + "type": "stat", + "title": "Approval p95 (s)", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "s", "decimals": 1}}, + "targets": [ + {"expr": "histogram_quantile(0.95, sum(rate(policy_approval_latency_seconds_bucket[5m])) by (le))"} + ] + }, + { + "type": "timeseries", + "title": "Approval Latency", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "s", "decimals": 1}}, + "targets": [ + {"expr": "histogram_quantile(0.90, sum(rate(policy_approval_latency_seconds_bucket[5m])) by (le))", "legendFormat": "p90"}, + {"expr": "histogram_quantile(0.50, sum(rate(policy_approval_latency_seconds_bucket[5m])) by (le))", "legendFormat": "p50"} + ] + }, + { + "type": "gauge", + "title": "Promotion Success Rate (30m)", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "percent", "min": 0, "max": 100}}, + "options": {"reduceOptions": {"calcs": ["last"]}, "orientation": "horizontal"}, + "targets": [ + {"expr": "100 * clamp_min(rate(policy_promotion_outcomes_total{outcome=\"success\"}[30m]),0) / clamp_min(rate(policy_promotion_outcomes_total[30m]),1)"} + ] + }, + { + "type": "barchart", + "title": "Promotion Outcomes", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "1/s"}}, + "options": {"displayMode": "series"}, + "targets": [ + {"expr": "rate(policy_promotion_outcomes_total[5m])", "legendFormat": "{{outcome}}"} + ] + } + ] +} diff --git a/ops/devops/observability/grafana/signals-pipeline.json b/ops/devops/observability/grafana/signals-pipeline.json new file mode 100644 index 000000000..63e44ffb6 --- /dev/null +++ b/ops/devops/observability/grafana/signals-pipeline.json @@ -0,0 +1,74 @@ +{ + "schemaVersion": 39, + "title": "Signals Pipeline", + "panels": [ + { + "type": "stat", + "title": "Scoring p95 (s)", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "s", "decimals": 2}}, + "targets": [ + {"expr": "histogram_quantile(0.95, sum(rate(signals_reachability_scoring_duration_seconds_bucket[5m])) by (le))"} + ] + }, + { + "type": "timeseries", + "title": "Scoring Duration p95/p50", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "s", "decimals": 2}}, + "targets": [ + {"expr": "histogram_quantile(0.95, sum(rate(signals_reachability_scoring_duration_seconds_bucket[5m])) by (le))", "legendFormat": "p95"}, + {"expr": "histogram_quantile(0.50, sum(rate(signals_reachability_scoring_duration_seconds_bucket[5m])) by (le))", "legendFormat": "p50"} + ] + }, + { + "type": "gauge", + "title": "Cache Hit Ratio (5m)", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "percent", "min": 0, "max": 100}}, + "options": {"reduceOptions": {"calcs": ["last"]}, "orientation": "horizontal"}, + "targets": [ + {"expr": "100 * clamp_min(rate(signals_cache_hits_total[5m]),0) / clamp_min(rate(signals_cache_hits_total[5m]) + rate(signals_cache_misses_total[5m]), 1)"} + ] + }, + { + "type": "timeseries", + "title": "Cache Hits/Misses", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "1/s"}}, + "targets": [ + {"expr": "rate(signals_cache_hits_total[5m])", "legendFormat": "hits"}, + {"expr": "rate(signals_cache_misses_total[5m])", "legendFormat": "misses"} + ] + }, + { + "type": "stat", + "title": "Sensors Reporting", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "none"}}, + "targets": [ + {"expr": "count(max_over_time(signals_sensor_last_seen_timestamp_seconds[15m]))"} + ] + }, + { + "type": "timeseries", + "title": "Sensor Staleness", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "s"}}, + "targets": [ + {"expr": "time() - max(signals_sensor_last_seen_timestamp_seconds) by (sensor)", "legendFormat": "{{sensor}}"} + ] + }, + { + "type": "barchart", + "title": "Ingestion Outcomes", + "datasource": "Prometheus", + "fieldConfig": {"defaults": {"unit": "1/s"}}, + "options": {"displayMode": "series"}, + "targets": [ + {"expr": "rate(signals_ingestion_total[5m])", "legendFormat": "total"}, + {"expr": "rate(signals_ingestion_failures_total[5m])", "legendFormat": "failures"} + ] + } + ] +} diff --git a/ops/devops/observability/policy-alerts.yaml b/ops/devops/observability/policy-alerts.yaml new file mode 100644 index 000000000..c614ad003 --- /dev/null +++ b/ops/devops/observability/policy-alerts.yaml @@ -0,0 +1,52 @@ +groups: + - name: policy-pipeline + rules: + - alert: PolicyCompileLatencyP99High + expr: histogram_quantile(0.99, sum(rate(policy_compile_duration_seconds_bucket[5m])) by (le)) > 5 + for: 10m + labels: + severity: warning + service: policy + annotations: + summary: "Policy compile latency elevated (p99)" + description: "p99 compile duration has been >5s for 10m" + + - alert: PolicySimulationQueueBacklog + expr: sum(policy_simulation_queue_depth) > 100 + for: 10m + labels: + severity: warning + service: policy + annotations: + summary: "Policy simulation backlog" + description: "Simulation queue depth above 100 for 10m" + + - alert: PolicyApprovalLatencyHigh + expr: histogram_quantile(0.95, sum(rate(policy_approval_latency_seconds_bucket[5m])) by (le)) > 30 + for: 15m + labels: + severity: critical + service: policy + annotations: + summary: "Policy approval latency high" + description: "p95 approval latency above 30s for 15m" + + - alert: PolicyPromotionFailureRate + expr: clamp_min(rate(policy_promotion_outcomes_total{outcome="failure"}[15m]), 0) / clamp_min(rate(policy_promotion_outcomes_total[15m]), 1) > 0.2 + for: 10m + labels: + severity: critical + service: policy + annotations: + summary: "Policy promotion failure rate elevated" + description: "Failures exceed 20% of promotions over 15m" + + - alert: PolicyPromotionStall + expr: rate(policy_promotion_outcomes_total{outcome="success"}[10m]) == 0 and sum(policy_simulation_queue_depth) > 0 + for: 10m + labels: + severity: warning + service: policy + annotations: + summary: "Policy promotion stalled" + description: "No successful promotions while work is queued" diff --git a/ops/devops/observability/policy-playbook.md b/ops/devops/observability/policy-playbook.md new file mode 100644 index 000000000..311bfb188 --- /dev/null +++ b/ops/devops/observability/policy-playbook.md @@ -0,0 +1,39 @@ +# Policy Pipeline Playbook + +Scope: policy compile → simulation → approval → promotion path. + +## Dashboards +- Grafana: import `ops/devops/observability/grafana/policy-pipeline.json` (datasource `Prometheus`). +- Key tiles: Compile p99, Simulation Queue Depth, Approval p95, Promotion Success Rate, Promotion Outcomes. + +## Alerts (Prometheus) +- Rules: `ops/devops/observability/policy-alerts.yaml` + - `PolicyCompileLatencyP99High` (p99 > 5s for 10m) + - `PolicySimulationQueueBacklog` (queue depth > 100 for 10m) + - `PolicyApprovalLatencyHigh` (p95 > 30s for 15m) + - `PolicyPromotionFailureRate` (failures >20% over 15m) + - `PolicyPromotionStall` (no successes while queue non-empty for 10m) + +## Runbook +1. **Compile latency alert** + - Check build nodes for CPU cap; verify cache hits for policy engine. + - Roll restart single runner; if persists, scale policy compile workers (+1) or purge stale cache. +2. **Simulation backlog** + - Inspect queue per stage (panel "Queue Depth by Stage"). + - If queue limited to one stage, increase concurrency for that stage or drain stuck items; otherwise, add workers. +3. **Approval latency high** + - Look for blocked approvals (UI/API outages). Re-run approval service health check; fail over to standby. +4. **Promotion failure rate/stall** + - Pull recent logs for promotion job; compare failure reasons (policy validation vs. target registry). + - If registry errors, pause promotions and file incident with registry owner; if policy validation, revert latest policy change or apply override to unblock critical tenants. +5. **Verification** + - After mitigation, ensure promotion success rate gauge recovers >95% and queues drain to baseline (<10). + +## Escalation +- Primary: Policy On-Call (week N roster). +- Secondary: DevOps Guild (release). +- Page if two critical alerts fire concurrently or any critical alert lasts >30m. + +## Notes +- Metrics assumed available: `policy_compile_duration_seconds_bucket`, `policy_simulation_queue_depth`, `policy_approval_latency_seconds_bucket`, `policy_promotion_outcomes_total{outcome=*}`. +- Keep alert thresholds stable unless load profile changes; adjust in Git with approval from Policy + DevOps leads. diff --git a/ops/devops/observability/signals-alerts.yaml b/ops/devops/observability/signals-alerts.yaml new file mode 100644 index 000000000..7e5ca5efb --- /dev/null +++ b/ops/devops/observability/signals-alerts.yaml @@ -0,0 +1,54 @@ +groups: + - name: signals-pipeline + rules: + - alert: SignalsScoringLatencyP95High + expr: histogram_quantile(0.95, sum(rate(signals_reachability_scoring_duration_seconds_bucket[5m])) by (le)) > 2 + for: 10m + labels: + severity: warning + service: signals + annotations: + summary: "Signals scoring latency high (p95)" + description: "Reachability scoring p95 exceeds 2s for 10m" + + - alert: SignalsCacheMissRateHigh + expr: | + clamp_min(rate(signals_cache_misses_total[5m]), 0) + / clamp_min(rate(signals_cache_hits_total[5m]) + rate(signals_cache_misses_total[5m]), 1) > 0.3 + for: 10m + labels: + severity: warning + service: signals + annotations: + summary: "Signals cache miss rate high" + description: "Cache miss ratio >30% over 10m; investigate Redis or key churn." + + - alert: SignalsCacheDown + expr: signals_cache_available == 0 + for: 2m + labels: + severity: critical + service: signals + annotations: + summary: "Signals cache unavailable" + description: "Redis cache reported unavailable for >2m" + + - alert: SignalsSensorStaleness + expr: time() - max(signals_sensor_last_seen_timestamp_seconds) by (sensor) > 900 + for: 5m + labels: + severity: warning + service: signals + annotations: + summary: "Signals sensor stale" + description: "No updates from sensor for >15 minutes" + + - alert: SignalsIngestionErrorRate + expr: clamp_min(rate(signals_ingestion_failures_total[5m]), 0) / clamp_min(rate(signals_ingestion_total[5m]), 1) > 0.05 + for: 5m + labels: + severity: critical + service: signals + annotations: + summary: "Signals ingestion failures elevated" + description: "Ingestion failure ratio above 5% over 5m" diff --git a/ops/devops/observability/signals-playbook.md b/ops/devops/observability/signals-playbook.md new file mode 100644 index 000000000..9a79ba3e1 --- /dev/null +++ b/ops/devops/observability/signals-playbook.md @@ -0,0 +1,40 @@ +# Signals Pipeline Playbook + +Scope: Signals ingestion, cache, scoring, and sensor freshness. + +## Dashboards +- Grafana: import `ops/devops/observability/grafana/signals-pipeline.json` (datasource `Prometheus`). +- Key tiles: Scoring p95, Cache hit ratio, Sensor staleness, Ingestion outcomes. + +## Alerts +- Rules: `ops/devops/observability/signals-alerts.yaml` + - `SignalsScoringLatencyP95High` (p95 > 2s for 10m) + - `SignalsCacheMissRateHigh` (miss ratio >30% for 10m) + - `SignalsCacheDown` + - `SignalsSensorStaleness` (no update >15m) + - `SignalsIngestionErrorRate` (failures >5%) + +## Runbook +1. **Scoring latency high** + - Check Mongo/Redis health; inspect CPU on workers. + - Scale Signals API pods or increase cache TTL to reduce load. +2. **Cache miss rate / cache down** + - Validate Redis connectivity/ACL; flush not recommended unless key explosion. + - Increase cache TTL; ensure connection string matches deployment. +3. **Sensor staleness** + - Identify stale sensors from alert label; verify upstream pipeline/log shipping. + - If sensor retired, update allowlist to silence expected gaps. +4. **Ingestion errors** + - Tail ingestion logs; classify errors (schema vs. storage). + - If artifacts rejected, check storage path and disk fullness; add capacity or rotate. +5. **Verification** + - Ensure cache hit ratio >90%, scoring p95 <2s, staleness panel near baseline (<5m) after mitigation. + +## Escalation +- Primary: Signals on-call. +- Secondary: DevOps Guild (observability). +- Page when critical alerts persist >20m or when cache down + scoring latency co-occur. + +## Notes +- Metrics expected: `signals_reachability_scoring_duration_seconds_bucket`, `signals_cache_hits_total`, `signals_cache_misses_total`, `signals_cache_available`, `signals_sensor_last_seen_timestamp_seconds`, `signals_ingestion_total`, `signals_ingestion_failures_total`. +- Keep thresholds version-controlled; align with Policy Engine consumers if scoring SLAs change. diff --git a/ops/devops/orchestrator/README.md b/ops/devops/orchestrator/README.md index d89480cf5..01e777c47 100644 --- a/ops/devops/orchestrator/README.md +++ b/ops/devops/orchestrator/README.md @@ -15,6 +15,13 @@ COMPOSE_FILE=ops/devops/orchestrator/docker-compose.orchestrator.yml docker comp # smoke check and emit connection strings scripts/orchestrator/smoke.sh cat out/orchestrator-smoke/readiness.txt + +# synthetic probe (postgres/mongo/nats health) +scripts/orchestrator/probe.sh +cat out/orchestrator-probe/status.txt + +# replay readiness (restart then smoke) +scripts/orchestrator/replay-smoke.sh ``` Connection strings @@ -26,6 +33,9 @@ Connection strings - Alerts: `ops/devops/orchestrator/alerts.yaml` - Grafana dashboard: `ops/devops/orchestrator/grafana/orchestrator-overview.json` - Metrics expected: `job_queue_depth`, `job_failures_total`, `lease_extensions_total`, `job_latency_seconds_bucket`. +- Runbook: `ops/devops/orchestrator/incident-response.md` +- Synthetic probes: `scripts/orchestrator/probe.sh` (writes `out/orchestrator-probe/status.txt`). +- Replay smoke: `scripts/orchestrator/replay-smoke.sh` (idempotent restart + smoke). ## CI hook (suggested) Add a workflow step (or local cron) to run `scripts/orchestrator/smoke.sh` with `SKIP_UP=1` against existing infra and publish the `readiness.txt` artifact for traceability. diff --git a/ops/devops/orchestrator/alerts.yaml b/ops/devops/orchestrator/alerts.yaml index 660698fcf..591ba1d7f 100644 --- a/ops/devops/orchestrator/alerts.yaml +++ b/ops/devops/orchestrator/alerts.yaml @@ -28,3 +28,42 @@ groups: annotations: summary: "Leases stalled" description: "No lease renewals while queue has items" + - alert: OrchestratorDLQDepthHigh + expr: job_dlq_depth > 10 + for: 10m + labels: + severity: warning + service: orchestrator + annotations: + summary: "DLQ depth high" + description: "Dead-letter queue depth above 10 for 10m" + - alert: OrchestratorBackpressure + expr: avg_over_time(rate_limiter_backpressure_ratio[5m]) > 0.5 + for: 5m + labels: + severity: warning + service: orchestrator + annotations: + summary: "Backpressure elevated" + description: "Rate limiter backpressure >50% over 5m" + - alert: OrchestratorErrorCluster + expr: sum by(jobType) (rate(job_failures_total[5m])) > 3 + for: 5m + labels: + severity: critical + service: orchestrator + annotations: + summary: "Error cluster detected" + description: "Failure rate >3/min for a job type" + - alert: OrchestratorFailureBurnRateHigh + expr: | + (rate(job_failures_total[5m]) / clamp_min(rate(job_processed_total[5m]), 1)) > 0.02 + and + (rate(job_failures_total[30m]) / clamp_min(rate(job_processed_total[30m]), 1)) > 0.01 + for: 10m + labels: + severity: critical + service: orchestrator + annotations: + summary: "Failure burn rate breaching SLO" + description: "5m/30m failure burn rate above 2%/1% SLO; investigate upstream jobs and dependencies." diff --git a/ops/devops/orchestrator/grafana/orchestrator-overview.json b/ops/devops/orchestrator/grafana/orchestrator-overview.json index 455d0546e..6406b3fdf 100644 --- a/ops/devops/orchestrator/grafana/orchestrator-overview.json +++ b/ops/devops/orchestrator/grafana/orchestrator-overview.json @@ -36,6 +36,27 @@ "datasource": "Prometheus", "targets": [{"expr": "histogram_quantile(0.95, sum(rate(job_latency_seconds_bucket[5m])) by (le))"}], "fieldConfig": {"defaults": {"unit": "s"}} + }, + { + "type": "timeseries", + "title": "DLQ depth", + "datasource": "Prometheus", + "targets": [{"expr": "job_dlq_depth"}], + "fieldConfig": {"defaults": {"unit": "none"}} + }, + { + "type": "timeseries", + "title": "Backpressure ratio", + "datasource": "Prometheus", + "targets": [{"expr": "rate_limiter_backpressure_ratio"}], + "fieldConfig": {"defaults": {"unit": "percentunit"}} + }, + { + "type": "timeseries", + "title": "Failures by job type", + "datasource": "Prometheus", + "targets": [{"expr": "rate(job_failures_total[5m])"}], + "fieldConfig": {"defaults": {"unit": "short"}} } ], "time": {"from": "now-6h", "to": "now"} diff --git a/ops/devops/orchestrator/incident-response.md b/ops/devops/orchestrator/incident-response.md new file mode 100644 index 000000000..3ddc3239a --- /dev/null +++ b/ops/devops/orchestrator/incident-response.md @@ -0,0 +1,37 @@ +# Orchestrator Incident Response & GA Readiness + +## Alert links +- Prometheus rules: `ops/devops/orchestrator/alerts.yaml` (includes burn-rate). +- Dashboard: `ops/devops/orchestrator/grafana/orchestrator-overview.json`. + +## Runbook (by alert) +- **QueueDepthHigh / DLQDepthHigh** + - Check backlog cause: slow workers vs. downstream dependency. + - Scale workers + clear DLQ after snapshot; if DLQ cause is transient, replay via `replay-smoke.sh` after fixes. +- **FailuresHigh / ErrorCluster / FailureBurnRateHigh** + - Inspect failing job type from alert labels. + - Pause new dispatch for the job type; ship hotfix or rollback offending worker image. + - Validate with `scripts/orchestrator/probe.sh` then `smoke.sh` to ensure infra is healthy. +- **LeaseStall** + - Look for stuck locks in Postgres `locks` view; force release or restart the worker set. + - Confirm NATS health (probe) and worker heartbeats. +- **Backpressure** + - Increase rate-limit budgets temporarily; ensure backlog drains; restore defaults after stability. + +## Synthetic checks +- `scripts/orchestrator/probe.sh` — psql ping, mongo ping, NATS pub/ping; writes `out/orchestrator-probe/status.txt`. +- `scripts/orchestrator/smoke.sh` — end-to-end infra smoke, emits readiness. +- `scripts/orchestrator/replay-smoke.sh` — restart stack then run smoke to prove restart/replay works. + +## GA readiness checklist +- [ ] Burn-rate alerting enabled in Prometheus/Alertmanager (see `alerts.yaml` rule `OrchestratorFailureBurnRateHigh`). +- [ ] Dashboard imported and linked in on-call rotation. +- [ ] Synthetic probe cron in CI/ops runner publishing `status.txt` artifact daily. +- [ ] Replay smoke scheduled post-deploy to validate persistence/volumes. +- [ ] Backup/restore for Postgres & Mongo verified weekly (not automated here). +- [ ] NATS JetStream retention + DLQ policy reviewed and documented. + +## Escalation +- Primary: Orchestrator on-call. +- Secondary: DevOps Guild (release). +- Page when any critical alert persists >15m or dual criticals fire simultaneously. diff --git a/ops/devops/policy-signing.md b/ops/devops/policy-signing.md new file mode 100644 index 000000000..1fbfe0183 --- /dev/null +++ b/ops/devops/policy-signing.md @@ -0,0 +1,46 @@ +# Policy Signing & Attestation (DevOps) + +## Purpose +- Keep policy artefacts (DSL files, bundles) signed with a short‑lived cosign key (or OIDC workload identity) so promotion is verifiable offline. +- Provide deterministic, reproducible signing/attestation flows that runners can execute without external registries. +- Make key rotation and verification one-liners for on-call and CI. + +## Scripts +- `scripts/policy/rotate-key.sh` – generate cosign keypair, emit base64 values for CI secrets in `out/policy-sign/keys/`. +- `scripts/policy/sign-policy.sh` – sign a policy blob with `COSIGN_KEY_B64` and verify the signature; emits signature + public key to `out/policy-sign/`. +- `scripts/policy/attest-verify.sh` – create a DSSE attestation for a policy blob and verify it against the generated bundle/public key. + +## Local / CI workflow +1. **Generate key (ephemeral or rotated):** + ```bash + OUT_DIR=out/policy-sign/keys PREFIX=ci-policy COSIGN_PASSWORD= scripts/policy/rotate-key.sh + ``` + Copy the base64 strings from `out/policy-sign/keys/README.txt` into `POLICY_COSIGN_KEY_B64` / `POLICY_COSIGN_PUB_B64` secrets. +2. **Sign a policy:** + ```bash + export COSIGN_KEY_B64=$(base64 -w0 out/policy-sign/keys/ci-policy-cosign.key) + COSIGN_PASSWORD= scripts/policy/sign-policy.sh --file docs/examples/policies/baseline.stella --out-dir out/policy-sign + ``` + Outputs: `baseline.stella.sig`, `cosign.pub`. +3. **Attest + verify:** + ```bash + export COSIGN_KEY_B64=$(base64 -w0 out/policy-sign/keys/ci-policy-cosign.key) + COSIGN_PASSWORD= scripts/policy/attest-verify.sh --file docs/examples/policies/baseline.stella --out-dir out/policy-sign + ``` + Outputs: DSSE bundle `.attestation.sigstore` and re-verifies it with the public key. +4. **CI stage:** `.gitea/workflows/policy-simulate.yml` now installs cosign, runs the three steps above, and publishes `out/policy-sign/` as an artifact alongside simulation outputs. + +## OIDC / workload identity +- Runners with keyless cosign enabled can skip `COSIGN_KEY_B64` and rely on `COSIGN_EXPERIMENTAL=1` + `COSIGN_FULCIO_URL`/`COSIGN_REKOR_URL`; keep offline jobs on key mode. +- Rotate keys per environment; keep prod keys in Gitea secrets and staging keys in repo‑local `out/` for reproducibility. + +## Verification quick check +- To verify a policy blob from artifacts: + ```bash + cosign verify-blob --key out/policy-sign/cosign.pub --signature out/policy-sign/baseline.stella.sig docs/examples/policies/baseline.stella + cosign verify-blob-attestation --key out/policy-sign/cosign.pub --type stella.policy --bundle out/policy-sign/baseline.stella.attestation.sigstore docs/examples/policies/baseline.stella + ``` + +## Notes +- All outputs are deterministic (UTC timestamps, fixed file names) to stay audit-friendly and offline-ready. +- Attestation predicate captures filename + SHA256 + timestamp for traceability. Update predicate schema if promotion metadata expands. diff --git a/ops/devops/rules/contracts-anchor.md b/ops/devops/rules/contracts-anchor.md new file mode 100644 index 000000000..785119e58 --- /dev/null +++ b/ops/devops/rules/contracts-anchor.md @@ -0,0 +1,19 @@ +# DevOps Rules Anchor (DEVOPS-RULES-33-001) + +Canonical guardrails for platform builds: + +1) Gateway proxies only; Policy Engine composes overlays/simulations. +2) AOC ingestion is lossless-only; no merge semantics permitted. +3) Single graph platform: Graph Indexer + Graph API; Cartographer retired. + +Implications +- Service teams must front external ingress with the gateway; no direct service exposure. +- AOC import pipelines must validate canonicalization and reject lossy merges. +- Graph workstreams target Indexer + API; no new Cartographer deployments or dependencies. + +Enforcement +- Add lint/checks in CI to flag direct service ingress configs and Cartographer references. +- AOC pipelines ship with canonicalization tests and forbid lossy transforms. +- Architecture reviews use this anchor as baseline; deviations require design review + ADR. + +Status: Adopted 2025-11-25. diff --git a/ops/devops/sdk/README.md b/ops/devops/sdk/README.md new file mode 100644 index 000000000..45efdccbe --- /dev/null +++ b/ops/devops/sdk/README.md @@ -0,0 +1,38 @@ +# SDK Publishing Pipeline (DEVOPS-SDK-63-001) + +Scope: registry credentials, signing keys, and secure storage for SDK publishing. + +Artifacts +- Scripts: `scripts/sdk/generate-cert.sh`, `scripts/sdk/sign-packages.sh`, `scripts/sdk/publish.sh`. +- CI: `.gitea/workflows/sdk-publish.yml` (build/test if present, sign, publish, and export offline kit). +- Local feed: defaults to `local-nugets/packages` for offline/file-based distribution. + +Secrets / env +- `SDK_SIGNING_CERT_B64` — base64 PKCS#12 (PFX) code-signing cert (generate with `generate-cert.sh`). +- `SDK_SIGNING_CERT_PASSWORD` — PFX password (empty allowed for dev). +- `SDK_NUGET_SOURCE` — NuGet feed (HTTP URL or local path; default `local-nugets/packages`). +- `SDK_NUGET_API_KEY` — API key for HTTP feeds (not used for file feeds). + +Usage +1) Generate signing cert (dev/stage): +```bash +scripts/sdk/generate-cert.sh +# read base64 from out/sdk-signing/README.txt and load into secrets +``` +2) Build/pack SDK (upstream generator publishes .nupkg into `out/sdk/` or `local-nugets/packages/`). +3) Sign packages: +```bash +SDK_SIGNING_CERT_B64=... SDK_SIGNING_CERT_PASSWORD=... scripts/sdk/sign-packages.sh +``` +4) Publish: +```bash +SDK_NUGET_SOURCE=https://nuget.example.com/v3/index.json SDK_NUGET_API_KEY=... scripts/sdk/publish.sh +# or to file feed (default): scripts/sdk/publish.sh +``` + +CI behavior +- Restores, (optionally) builds/tests if SDK solution present, signs any `.nupkg` under `out/sdk` or `local-nugets/packages`, then publishes to `SDK_NUGET_SOURCE`, and uploads `out/sdk` as artifact. +- No-op if no packages present (keeps pipeline green for config-only updates). + +Secure storage +- Do not commit keys. Store certs in the CI secret store; for manual ops, keep encrypted blobs outside the repo (e.g., vault entry with `SDK_SIGNING_CERT_B64` + password). diff --git a/ops/devops/signals/Dockerfile b/ops/devops/signals/Dockerfile new file mode 100644 index 000000000..536ea4ee0 --- /dev/null +++ b/ops/devops/signals/Dockerfile @@ -0,0 +1,22 @@ +# syntax=docker/dockerfile:1.7 + +ARG DOTNET_VERSION=10.0 +ARG RUNTIME_IMAGE=mcr.microsoft.com/dotnet/aspnet:${DOTNET_VERSION}-rc-alpine +ARG SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-rc-alpine + +FROM ${SDK_IMAGE} AS build +WORKDIR /src +COPY nuget.config nuget.config +COPY src/Signals/StellaOps.Signals/StellaOps.Signals.csproj src/Signals/StellaOps.Signals/ +COPY src/Signals/StellaOps.Signals.sln src/Signals/ +RUN dotnet restore src/Signals/StellaOps.Signals/StellaOps.Signals.csproj --configfile nuget.config +COPY src/Signals/ src/Signals/ +RUN dotnet publish src/Signals/StellaOps.Signals/StellaOps.Signals.csproj -c Release -o /app/publish --no-restore + +FROM ${RUNTIME_IMAGE} AS final +WORKDIR /app +ENV ASPNETCORE_URLS=http://+:5088 +ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 +COPY --from=build /app/publish . +EXPOSE 5088 +ENTRYPOINT ["dotnet", "StellaOps.Signals.dll"] diff --git a/ops/devops/signals/README.md b/ops/devops/signals/README.md new file mode 100644 index 000000000..49a481efb --- /dev/null +++ b/ops/devops/signals/README.md @@ -0,0 +1,33 @@ +# Signals CI/CD & Local Stack (DEVOPS-SIG-26-001) + +Artifacts: +- Compose stack: `ops/devops/signals/docker-compose.signals.yml` (Signals API + Mongo + Redis + artifact volume). +- Sample config: `ops/devops/signals/signals.yaml` (mounted into the container at `/app/signals.yaml` if desired). +- Dockerfile: `ops/devops/signals/Dockerfile` (multi-stage build on .NET 10 RC). +- Build/export helper: `scripts/signals/build.sh` (saves image tar to `out/signals/signals-image.tar`). + +Quick start (offline-friendly): +```bash +# build image +scripts/signals/build.sh + +# run stack +COMPOSE_FILE=ops/devops/signals/docker-compose.signals.yml docker compose up -d + +# hit health +curl -s http://localhost:5088/health +``` + +Configuration (ENV or YAML): +- `Signals__Mongo__ConnectionString` default `mongodb://signals-mongo:27017/signals` +- `Signals__Cache__ConnectionString` default `signals-redis:6379` +- `Signals__Storage__RootPath` default `/data/artifacts` +- Authority disabled by default for local; enable with `Signals__Authority__Enabled=true` and issuer settings. + +CI workflow: +- `.gitea/workflows/signals-ci.yml` restores, builds, tests, builds container, and uploads `signals-image.tar` artifact. + +Dependencies: +- Mongo 7 (wiredTiger) +- Redis 7 (cache) +- Artifact volume `signals_artifacts` for callgraph blobs. diff --git a/ops/devops/signals/docker-compose.signals.yml b/ops/devops/signals/docker-compose.signals.yml new file mode 100644 index 000000000..1a27ffb98 --- /dev/null +++ b/ops/devops/signals/docker-compose.signals.yml @@ -0,0 +1,52 @@ +version: "3.9" + +services: + signals-api: + build: + context: ../.. + dockerfile: ops/devops/signals/Dockerfile + image: stellaops/signals:local + environment: + ASPNETCORE_URLS: "http://+:5088" + Signals__Mongo__ConnectionString: "mongodb://signals-mongo:27017/signals" + Signals__Mongo__Database: "signals" + Signals__Cache__ConnectionString: "signals-redis:6379" + Signals__Storage__RootPath: "/data/artifacts" + Signals__Authority__Enabled: "false" + Signals__OpenApi__Enabled: "true" + ports: + - "5088:5088" + depends_on: + - signals-mongo + - signals-redis + volumes: + - signals_artifacts:/data/artifacts + - ./signals.yaml:/app/signals.yaml:ro + + signals-mongo: + image: mongo:7 + command: ["mongod", "--quiet", "--storageEngine=wiredTiger"] + ports: + - "57027:27017" + volumes: + - signals_mongo:/data/db + healthcheck: + test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping')"] + interval: 10s + timeout: 5s + retries: 5 + + signals-redis: + image: redis:7-alpine + ports: + - "56379:6379" + command: ["redis-server", "--save", "", "--appendonly", "no"] + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + signals_artifacts: + signals_mongo: diff --git a/ops/devops/signals/signals.yaml b/ops/devops/signals/signals.yaml new file mode 100644 index 000000000..e5792f67a --- /dev/null +++ b/ops/devops/signals/signals.yaml @@ -0,0 +1,15 @@ +# Sample offline configuration for Signals + +Signals: + Mongo: + ConnectionString: "mongodb://signals-mongo:27017/signals" + Database: "signals" + Cache: + ConnectionString: "signals-redis:6379" + DefaultTtlSeconds: 600 + Storage: + RootPath: "/data/artifacts" + Authority: + Enabled: false + OpenApi: + Enabled: true diff --git a/scripts/devops/cleanup-workspace.sh b/scripts/devops/cleanup-workspace.sh new file mode 100644 index 000000000..68ff10b63 --- /dev/null +++ b/scripts/devops/cleanup-workspace.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail +# Cleans common build/test artifacts to reclaim disk space in this repo. +# Defaults to a safe set; pass SAFE_ONLY=0 to include bin/obj. + +DRY_RUN=${DRY_RUN:-0} +SAFE_ONLY=${SAFE_ONLY:-1} + +log() { printf "[cleanup] %s\n" "$*"; } +run() { + if [[ "$DRY_RUN" == "1" ]]; then + log "DRY_RUN: $*" + else + eval "$@" + fi +} + +ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" +cd "$ROOT" + +paths=( + "out" + "ops/devops/artifacts" + "ops/devops/ci-110-runner/artifacts" + "ops/devops/sealed-mode-ci/artifacts" + "TestResults" + "tests/TestResults" + "local-nugets/packages" + ".nuget/packages" +) + +if [[ "$SAFE_ONLY" != "1" ]]; then + while IFS= read -r dir; do + paths+=("$dir") + done < <(find . -maxdepth 4 -type d \( -name bin -o -name obj -o -name TestResults \) 2>/dev/null) +fi + +log "Safe only: $SAFE_ONLY ; Dry run: $DRY_RUN" +for p in "${paths[@]}"; do + if [[ -d "$p" ]]; then + log "Removing $p" + run "rm -rf '$p'" + fi +done + +log "Done." diff --git a/scripts/orchestrator/probe.sh b/scripts/orchestrator/probe.sh new file mode 100644 index 000000000..9c2c983e4 --- /dev/null +++ b/scripts/orchestrator/probe.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail +# Synthetic probe for orchestrator infra (postgres, mongo, nats). +# Runs lightweight checks and writes a status file under out/orchestrator-probe/. + +COMPOSE_FILE=${COMPOSE_FILE:-ops/devops/orchestrator/docker-compose.orchestrator.yml} +STATE_DIR=${STATE_DIR:-out/orchestrator-probe} + +mkdir -p "$STATE_DIR" + +log() { printf "[probe] %s\n" "$*"; } +require() { command -v "$1" >/dev/null 2>&1 || { echo "missing $1" >&2; exit 1; }; } + +require docker + +timestamp() { date -u +%Y-%m-%dT%H:%M:%SZ; } + +log "compose file: $COMPOSE_FILE" + +PG_OK=0 +MONGO_OK=0 +NATS_OK=0 + +if docker compose -f "$COMPOSE_FILE" ps orchestrator-postgres >/dev/null 2>&1; then + if docker compose -f "$COMPOSE_FILE" exec -T orchestrator-postgres psql -U orch -tAc "select 1" | grep -q 1; then + PG_OK=1 + fi +fi + +if docker compose -f "$COMPOSE_FILE" ps orchestrator-mongo >/dev/null 2>&1; then + if docker compose -f "$COMPOSE_FILE" exec -T orchestrator-mongo mongosh --quiet --eval "db.adminCommand('ping').ok" | grep -q 1; then + MONGO_OK=1 + fi +fi + +if docker compose -f "$COMPOSE_FILE" ps orchestrator-nats >/dev/null 2>&1; then + if docker compose -f "$COMPOSE_FILE" exec -T orchestrator-nats nats --server localhost:4222 ping >/dev/null 2>&1; then + # publish & request to ensure traffic path works + docker compose -f "$COMPOSE_FILE" exec -T orchestrator-nats nats --server localhost:4222 pub probe.ping "ok" >/dev/null 2>&1 || true + NATS_OK=1 + fi +fi + +cat > "$STATE_DIR/status.txt" < [--predicate ] [--type stella.policy] [--out-dir out/policy-sign] +Env: + COSIGN_KEY_B64 base64-encoded PEM private key (if not using COSIGN_KEY path) + COSIGN_PASSWORD passphrase for the private key (optional) +USAGE +} + +FILE="" +PREDICATE="" +TYPE="stella.policy" +OUT_DIR="out/policy-sign" + +while [[ $# -gt 0 ]]; do + case "$1" in + --file) FILE="$2"; shift 2;; + --predicate) PREDICATE="$2"; shift 2;; + --type) TYPE="$2"; shift 2;; + --out-dir) OUT_DIR="$2"; shift 2;; + -h|--help) usage; exit 0;; + *) echo "Unknown arg: $1" >&2; usage; exit 1;; + esac +done + +if [[ -z "$FILE" ]]; then echo "--file is required" >&2; exit 1; fi +if [[ ! -f "$FILE" ]]; then echo "file not found: $FILE" >&2; exit 1; fi + +if ! command -v cosign >/dev/null 2>&1; then + echo "cosign is required on PATH" >&2 + exit 1 +fi + +mkdir -p "$OUT_DIR" +BASENAME=$(basename "$FILE") +KEY_PATH=${COSIGN_KEY:-"$OUT_DIR/cosign.key"} +PUB_OUT="$OUT_DIR/cosign.pub" +BUNDLE="$OUT_DIR/${BASENAME}.attestation.sigstore" + +if [[ -n "${COSIGN_KEY_B64:-}" ]]; then + printf "%s" "$COSIGN_KEY_B64" | base64 -d > "$KEY_PATH" + chmod 600 "$KEY_PATH" +fi + +if [[ ! -f "$KEY_PATH" ]]; then + echo "Missing signing key; set COSIGN_KEY_B64 or COSIGN_KEY path" >&2 + exit 1 +fi + +export COSIGN_PASSWORD=${COSIGN_PASSWORD:-} + +if [[ -z "$PREDICATE" ]]; then + PREDICATE="$OUT_DIR/${BASENAME}.predicate.json" + sha256sum "$FILE" | awk '{print $1}' > "$OUT_DIR/${BASENAME}.sha256" + cat > "$PREDICATE" < "$PUB_OUT" + +cosign attest-blob \ + --predicate "$PREDICATE" \ + --type "$TYPE" \ + --bundle "$BUNDLE" \ + --key "$KEY_PATH" \ + "$FILE" + +cosign verify-blob-attestation \ + --key "$PUB_OUT" \ + --type "$TYPE" \ + --bundle "$BUNDLE" \ + "$FILE" + +printf "Attestation bundle -> %s\nVerified with -> %s\n" "$BUNDLE" "$PUB_OUT" diff --git a/scripts/policy/batch-simulate.sh b/scripts/policy/batch-simulate.sh new file mode 100644 index 000000000..d474485af --- /dev/null +++ b/scripts/policy/batch-simulate.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail +ROOT=$(cd "$(dirname "$0")/.." && pwd) +CLI_PROJECT="$ROOT/Cli/StellaOps.Cli/StellaOps.Cli.csproj" +POLICY_FILES=("docs/examples/policies/baseline.stella" "docs/examples/policies/internal-only.stella" "docs/examples/policies/serverless.stella") +SBOM_FILE="docs/examples/policies/sample-sbom.json" +OUT_DIR="${OUT_DIR:-out/policy-sim}" +THRESHOLD=${THRESHOLD:-0} + +usage() { + cat <<'USAGE' +Batch policy simulate harness (DEVOPS-POLICY-27-002) +- Runs stella policy simulate against sample policies and a sample SBOM +- Fails if violation count exceeds THRESHOLD (default 0) + +Env/flags: + OUT_DIR=out/policy-sim + THRESHOLD=0 + SBOM_FILE=docs/examples/policies/sample-sbom.json +USAGE +} + +if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then usage; exit 0; fi +mkdir -p "$OUT_DIR" + +violations=0 +for policy in "${POLICY_FILES[@]}"; do + name=$(basename "$policy" .stella) + report="$OUT_DIR/${name}-simulate.json" + dotnet run --project "$CLI_PROJECT" -- policy simulate --policy "$policy" --sbom "$SBOM_FILE" --format json --no-color > "$report" + # count violations if field exists + count=$(python - < THRESHOLD )); then + echo "Violation threshold exceeded ($violations > $THRESHOLD)" >&2 + exit 1 +fi diff --git a/scripts/policy/rotate-key.sh b/scripts/policy/rotate-key.sh new file mode 100644 index 000000000..f3251aafa --- /dev/null +++ b/scripts/policy/rotate-key.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +# Generates a new cosign keypair for policy signing. +# Outputs PEMs in out/policy-sign/keys and base64 ready for CI secrets. + +OUT_DIR=${OUT_DIR:-out/policy-sign/keys} +PREFIX=${PREFIX:-policy-cosign} +PASSWORD=${COSIGN_PASSWORD:-} + +mkdir -p "$OUT_DIR" +KEY_PREFIX="$OUT_DIR/$PREFIX" + +if ! command -v cosign >/dev/null 2>&1; then + echo "cosign is required on PATH" >&2 + exit 1 +fi + +export COSIGN_PASSWORD="$PASSWORD" +cosign version >/dev/null +cosign generate-key-pair --output-key-prefix "$KEY_PREFIX" >/dev/null + +BASE64_PRIV=$(base64 < "${KEY_PREFIX}.key" | tr -d '\n') +BASE64_PUB=$(base64 < "${KEY_PREFIX}.pub" | tr -d '\n') + +cat > "$OUT_DIR/README.txt" < [--out-dir out/policy-sign] +Env: + COSIGN_KEY_B64 base64-encoded PEM private key (if not using KMS) + COSIGN_PASSWORD passphrase for the key (can be empty for test keys) + COSIGN_PUBLIC_KEY_PATH optional path to write public key for verify step +USAGE +} + +FILE="" +OUT_DIR="out/policy-sign" + +while [[ $# -gt 0 ]]; do + case "$1" in + --file) FILE="$2"; shift 2;; + --out-dir) OUT_DIR="$2"; shift 2;; + -h|--help) usage; exit 0;; + *) echo "Unknown arg: $1" >&2; usage; exit 1;; + esac +done + +if [[ -z "$FILE" ]]; then echo "--file is required" >&2; exit 1; fi +if [[ ! -f "$FILE" ]]; then echo "file not found: $FILE" >&2; exit 1; fi + +mkdir -p "$OUT_DIR" +BASENAME=$(basename "$FILE") +SIG="$OUT_DIR/${BASENAME}.sig" +PUB_OUT="${COSIGN_PUBLIC_KEY_PATH:-$OUT_DIR/cosign.pub}" + +if [[ -n "${COSIGN_KEY_B64:-}" ]]; then + KEYFILE="$OUT_DIR/cosign.key" + printf "%s" "$COSIGN_KEY_B64" | base64 -d > "$KEYFILE" + chmod 600 "$KEYFILE" + export COSIGN_KEY="$KEYFILE" +fi + +export COSIGN_PASSWORD=${COSIGN_PASSWORD:-} +cosign version >/dev/null + +cosign sign-blob "$FILE" --output-signature "$SIG" +cosign public-key --key "$COSIGN_KEY" > "$PUB_OUT" +cosign verify-blob --key "$PUB_OUT" --signature "$SIG" "$FILE" + +printf "Signed %s -> %s\nPublic key -> %s\n" "$FILE" "$SIG" "$PUB_OUT" diff --git a/scripts/sdk/generate-cert.sh b/scripts/sdk/generate-cert.sh new file mode 100644 index 000000000..6b9c064e3 --- /dev/null +++ b/scripts/sdk/generate-cert.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +# Generates an offline-friendly code-signing certificate (self-signed) for NuGet package signing. + +OUT_DIR=${OUT_DIR:-out/sdk-signing} +SUBJECT=${SUBJECT:-"/CN=StellaOps SDK Signing/O=StellaOps"} +DAYS=${DAYS:-3650} +PFX_NAME=${PFX_NAME:-sdk-signing.pfx} +PASSWORD=${PASSWORD:-""} + +mkdir -p "$OUT_DIR" + +PRIV="$OUT_DIR/sdk-signing.key" +CRT="$OUT_DIR/sdk-signing.crt" +PFX="$OUT_DIR/$PFX_NAME" + +openssl req -x509 -newkey rsa:4096 -sha256 -days "$DAYS" \ + -nodes -subj "$SUBJECT" -keyout "$PRIV" -out "$CRT" + +openssl pkcs12 -export -out "$PFX" -inkey "$PRIV" -in "$CRT" -passout pass:"$PASSWORD" + +BASE64_PFX=$(base64 < "$PFX" | tr -d '\n') + +cat > "$OUT_DIR/README.txt" <} +Base64: +$BASE64_PFX +Secrets to set: + SDK_SIGNING_CERT_B64=$BASE64_PFX + SDK_SIGNING_CERT_PASSWORD=$PASSWORD +EOF + +printf "Generated signing cert -> %s (base64 in README)\n" "$PFX" diff --git a/scripts/sdk/publish.sh b/scripts/sdk/publish.sh new file mode 100644 index 000000000..685a89341 --- /dev/null +++ b/scripts/sdk/publish.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail +# Publishes signed NuGet packages to a configured feed (file or HTTP). + +PACKAGES_GLOB=${PACKAGES_GLOB:-"out/sdk/*.nupkg"} +SOURCE=${SDK_NUGET_SOURCE:-"local-nugets/packages"} +API_KEY=${SDK_NUGET_API_KEY:-""} + +mapfile -t packages < <(ls $PACKAGES_GLOB 2>/dev/null || true) +if [[ ${#packages[@]} -eq 0 ]]; then + echo "No packages found under glob '$PACKAGES_GLOB'; nothing to publish." + exit 0 +fi + +publish_file() { + local pkg="$1" + mkdir -p "$SOURCE" + cp "$pkg" "$SOURCE"/ +} + +publish_http() { + local pkg="$1" + dotnet nuget push "$pkg" --source "$SOURCE" --api-key "$API_KEY" --skip-duplicate +} + +if [[ "$SOURCE" =~ ^https?:// ]]; then + if [[ -z "$API_KEY" ]]; then + echo "SDK_NUGET_API_KEY is required for HTTP source $SOURCE" >&2 + exit 1 + fi + for pkg in "${packages[@]}"; do publish_http "$pkg"; done +else + for pkg in "${packages[@]}"; do publish_file "$pkg"; done +fi + +echo "Published ${#packages[@]} package(s) to $SOURCE" diff --git a/scripts/sdk/sign-packages.sh b/scripts/sdk/sign-packages.sh new file mode 100644 index 000000000..6f727ae2f --- /dev/null +++ b/scripts/sdk/sign-packages.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail +# Signs NuGet packages using a PKCS#12 (PFX) certificate. + +PACKAGES_GLOB=${PACKAGES_GLOB:-"out/sdk/*.nupkg"} +OUT_DIR=${OUT_DIR:-out/sdk} +TIMESTAMP_URL=${TIMESTAMP_URL:-""} # optional; keep empty for offline + +PFX_PATH=${PFX_PATH:-""} +PFX_B64=${SDK_SIGNING_CERT_B64:-} +PFX_PASSWORD=${SDK_SIGNING_CERT_PASSWORD:-} + +mkdir -p "$OUT_DIR" + +if [[ -z "$PFX_PATH" ]]; then + if [[ -z "$PFX_B64" ]]; then + echo "No signing cert provided (SDK_SIGNING_CERT_B64/PFX_PATH); skipping signing." + exit 0 + fi + PFX_PATH="$OUT_DIR/sdk-signing.pfx" + printf "%s" "$PFX_B64" | base64 -d > "$PFX_PATH" +fi + +mapfile -t packages < <(ls $PACKAGES_GLOB 2>/dev/null || true) +if [[ ${#packages[@]} -eq 0 ]]; then + echo "No packages found under glob '$PACKAGES_GLOB'; nothing to sign." + exit 0 +fi + +for pkg in "${packages[@]}"; do + echo "Signing $pkg" + ts_args=() + if [[ -n "$TIMESTAMP_URL" ]]; then + ts_args=(--timestamp-url "$TIMESTAMP_URL") + fi + dotnet nuget sign "$pkg" \ + --certificate-path "$PFX_PATH" \ + --certificate-password "$PFX_PASSWORD" \ + --hash-algorithm sha256 \ + "${ts_args[@]}" +done + +echo "Signed ${#packages[@]} package(s)." diff --git a/scripts/signals/build.sh b/scripts/signals/build.sh new file mode 100644 index 000000000..462160ca8 --- /dev/null +++ b/scripts/signals/build.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# Build Signals image and export a tarball for offline use. + +ROOT=${ROOT:-$(git rev-parse --show-toplevel)} +OUT_DIR=${OUT_DIR:-$ROOT/out/signals} +IMAGE_TAG=${IMAGE_TAG:-stellaops/signals:local} +DOCKERFILE=${DOCKERFILE:-ops/devops/signals/Dockerfile} + +mkdir -p "$OUT_DIR" + +docker build -f "$DOCKERFILE" -t "$IMAGE_TAG" "$ROOT" +docker save "$IMAGE_TAG" -o "$OUT_DIR/signals-image.tar" + +printf "Image %s saved to %s/signals-image.tar\n" "$IMAGE_TAG" "$OUT_DIR" diff --git a/src/AirGap/AGENTS.md b/src/AirGap/AGENTS.md new file mode 100644 index 000000000..4be646acd --- /dev/null +++ b/src/AirGap/AGENTS.md @@ -0,0 +1,42 @@ +# AirGap Module · AGENTS Charter + +## Working Directory +- `src/AirGap/**` (Controller, Importer, Time). Do not edit other modules without sprint note. + +## Roles +- **Controller engineer (ASP.NET Core)**: seal/unseal state machine, status APIs, Authority scope enforcement. +- **Importer engineer**: bundle verification (TUF/DSSE), catalog repositories, object-store loaders. +- **Time engineer**: time anchor parsing/verification (Roughtime, RFC3161), staleness calculators. +- **QA/Automation**: API + storage tests (Mongo2Go/in-memory), deterministic ordering, sealed/offline paths. +- **Docs/Runbooks**: keep air-gap ops guides, scaffolds, and schemas aligned with behavior. + +## Required Reading (treat as read before DOING) +- `docs/README.md`, `docs/07_HIGH_LEVEL_ARCHITECTURE.md`, `docs/modules/platform/architecture-overview.md` +- `docs/modules/airgap/airgap-mode.md` (if present) +- Prep/Scaffold docs: + - `docs/airgap/controller-scaffold.md` + - `docs/airgap/prep/2025-11-20-controller-scaffold-prep.md` + - `docs/airgap/importer-scaffold.md` + - `docs/airgap/time-anchor-scaffold.md` + - `docs/airgap/prep/2025-11-20-staleness-drift-prep.md` + - `docs/airgap/sealed-startup-diagnostics.md` + - `docs/airgap/bundle-repositories.md` + - `docs/airgap/time-api.md`, `docs/airgap/time-config-sample.json` + +## Working Agreements +- Offline-first: no egress in sealed mode; fixtures use local files only. +- Determinism: stable ordering, UTC ISO-8601 timestamps, fixed seeds for tests, deterministic hashing. +- Tenancy/scopes: enforce Authority scopes (`airgap:seal`, `airgap:status:read`, importer scopes) on every API. +- Validation: prefer `$jsonSchema`/FluentValidation; fail closed on trust-root mismatch. +- Logging/Telemetry: structured logs; counters/histograms prefixed `airgap.*`; tag `tenant`, `sealed`, `result`. +- Cross-module edits require sprint note; otherwise stay within `src/AirGap`. + +## Testing Rules +- Use Mongo2Go/in-memory stores; no network. +- Cover sealed/unsealed transitions, staleness budgets, trust-root failures, deterministic ordering. +- API tests via WebApplicationFactory; importer tests use local fixture bundles (no downloads). + +## Delivery Discipline +- Update sprint tracker statuses (`TODO → DOING → DONE/BLOCKED`); log decisions in Execution Log and Decisions & Risks. +- When contracts/schemas change, update docs under `docs/airgap/**` and link from sprint Decisions & Risks. +- If a decision is needed, mark BLOCKED in the sprint and record the decision ask; continue with other unblocked work. diff --git a/src/Concelier/StellaOps.Concelier.WebService/Contracts/EvidenceSnapshotContracts.cs b/src/Concelier/StellaOps.Concelier.WebService/Contracts/EvidenceSnapshotContracts.cs index e5b077e57..9da467534 100644 --- a/src/Concelier/StellaOps.Concelier.WebService/Contracts/EvidenceSnapshotContracts.cs +++ b/src/Concelier/StellaOps.Concelier.WebService/Contracts/EvidenceSnapshotContracts.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using StellaOps.Concelier.Core.Attestation; namespace StellaOps.Concelier.WebService; diff --git a/src/Concelier/StellaOps.Concelier.WebService/Program.cs b/src/Concelier/StellaOps.Concelier.WebService/Program.cs index d5265189d..f3c4dc990 100644 --- a/src/Concelier/StellaOps.Concelier.WebService/Program.cs +++ b/src/Concelier/StellaOps.Concelier.WebService/Program.cs @@ -19,8 +19,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using System.Diagnostics; -using System.Text.Json; -using System.Text.Json.Serialization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; @@ -32,11 +30,11 @@ using StellaOps.Concelier.Core.Observations; using StellaOps.Concelier.Core.Linksets; using StellaOps.Concelier.Models; using StellaOps.Concelier.WebService.Diagnostics; +using ServiceStatus = StellaOps.Concelier.WebService.Diagnostics.ServiceStatus; using Serilog; using StellaOps.Concelier.Merge; using StellaOps.Concelier.Merge.Services; using StellaOps.Concelier.WebService.Extensions; -using StellaOps.Concelier.WebService.Services; using StellaOps.Concelier.WebService.Jobs; using StellaOps.Concelier.WebService.Options; using StellaOps.Concelier.WebService.Filters; @@ -61,8 +59,8 @@ using StellaOps.Concelier.Storage.Mongo.Advisories; using StellaOps.Concelier.Storage.Mongo.Aliases; using StellaOps.Provenance.Mongo; using StellaOps.Concelier.Core.Attestation; +using AttestationClaims = StellaOps.Concelier.Core.Attestation.AttestationClaims; using StellaOps.Concelier.Storage.Mongo.Orchestrator; -using System.Security.Cryptography; using System.Diagnostics.Metrics; using StellaOps.Concelier.Models.Observations; @@ -117,28 +115,33 @@ var contentRootPath = builder.Environment.ContentRootPath; ConcelierOptions concelierOptions; if (builder.Environment.IsEnvironment("Testing")) -{ - // Allow a fully pre-bound options instance to be supplied by the test host. - #pragma warning disable ASP0000 // test-only: create provider to fetch pre-bound options - using var tempProvider = builder.Services.BuildServiceProvider(); - #pragma warning restore ASP0000 - concelierOptions = tempProvider.GetService>()?.Value ?? new ConcelierOptions { - Storage = new ConcelierOptions.StorageOptions + // Allow a fully pre-bound options instance to be supplied by the test host. + #pragma warning disable ASP0000 // test-only: create provider to fetch pre-bound options + using var tempProvider = builder.Services.BuildServiceProvider(); + #pragma warning restore ASP0000 + concelierOptions = tempProvider.GetService>()?.Value ?? new ConcelierOptions { - Dsn = Environment.GetEnvironmentVariable("CONCELIER_TEST_STORAGE_DSN") ?? "mongodb://localhost:27017/test-health", - Driver = "mongo", - CommandTimeoutSeconds = 30 - }, - Telemetry = new ConcelierOptions.TelemetryOptions - { - Enabled = false - } - }; + Storage = new ConcelierOptions.StorageOptions + { + Dsn = Environment.GetEnvironmentVariable("CONCELIER_TEST_STORAGE_DSN") ?? "mongodb://localhost:27017/test-health", + Driver = "mongo", + CommandTimeoutSeconds = 30 + }, + Telemetry = new ConcelierOptions.TelemetryOptions + { + Enabled = false + } + }; - ConcelierOptionsPostConfigure.Apply(concelierOptions, contentRootPath); - // Skip validation in Testing to allow factory-provided wiring. -} + concelierOptions.Storage ??= new ConcelierOptions.StorageOptions(); + concelierOptions.Storage.Dsn = Environment.GetEnvironmentVariable("CONCELIER_TEST_STORAGE_DSN") ?? "mongodb://localhost:27017/orch-tests"; + concelierOptions.Storage.Driver = "mongo"; + concelierOptions.Storage.CommandTimeoutSeconds = concelierOptions.Storage.CommandTimeoutSeconds <= 0 ? 30 : concelierOptions.Storage.CommandTimeoutSeconds; + + ConcelierOptionsPostConfigure.Apply(concelierOptions, contentRootPath); + // Skip validation in Testing to allow factory-provided wiring. + } else { concelierOptions = builder.Configuration.BindOptions(postConfigure: (opts, _) => @@ -171,12 +174,27 @@ builder.Services.AddMemoryCache(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); -builder.Services.AddMongoStorage(storageOptions => +var isTesting = builder.Environment.IsEnvironment("Testing"); +var mongoBypass = isTesting || string.Equals( + Environment.GetEnvironmentVariable("CONCELIER_BYPASS_MONGO"), + "1", + StringComparison.OrdinalIgnoreCase); + +if (!isTesting) { - storageOptions.ConnectionString = concelierOptions.Storage.Dsn; - storageOptions.DatabaseName = concelierOptions.Storage.Database; - storageOptions.CommandTimeout = TimeSpan.FromSeconds(concelierOptions.Storage.CommandTimeoutSeconds); -}); + builder.Services.AddMongoStorage(storageOptions => + { + storageOptions.ConnectionString = concelierOptions.Storage.Dsn; + storageOptions.DatabaseName = concelierOptions.Storage.Database; + storageOptions.CommandTimeout = TimeSpan.FromSeconds(concelierOptions.Storage.CommandTimeoutSeconds); + }); +} +else +{ + // In test host we entirely bypass Mongo validation/bootstrapping; tests inject fakes. + builder.Services.RemoveAll(); + builder.Services.RemoveAll(); +} builder.Services.AddOptions() .Bind(builder.Configuration.GetSection("advisoryObservationEvents")) .PostConfigure(options => @@ -229,7 +247,7 @@ builder.Services.PostConfigure(options => }); builder.Services.AddSingleton(); -builder.Services.AddSingleton(sp => new ServiceStatus(sp.GetRequiredService())); +builder.Services.AddSingleton(sp => new StellaOps.Concelier.WebService.Diagnostics.ServiceStatus(sp.GetRequiredService())); builder.Services.AddAocGuard(); var authorityConfigured = concelierOptions.Authority is { Enabled: true }; @@ -743,7 +761,7 @@ app.MapGet("/v1/lnm/linksets", async ( resolvedPageSize, cancellationToken).ConfigureAwait(false); - var items = new List(result.Items.Length); + var items = new List(result.Items.Count); foreach (var linkset in result.Items) { var summary = await BuildObservationSummaryAsync(observationQueryService, tenant!, linkset, cancellationToken).ConfigureAwait(false); @@ -788,7 +806,7 @@ app.MapPost("/v1/lnm/linksets/search", async ( resolvedPageSize, cancellationToken).ConfigureAwait(false); - var items = new List(result.Items.Length); + var items = new List(result.Items.Count); foreach (var linkset in result.Items) { var summary = await BuildObservationSummaryAsync(observationQueryService, tenant!, linkset, cancellationToken).ConfigureAwait(false); @@ -1346,7 +1364,7 @@ var evidenceSnapshotEndpoint = app.MapGet("/obs/evidence/advisories/{advisoryKey var hash = await ComputeSha256Async(manifestStream, cancellationToken).ConfigureAwait(false); var response = new EvidenceSnapshotResponse( - advisoryKey: advisoryKey.Trim(), + AdvisoryKey: advisoryKey.Trim(), Tenant: tenant, ManifestPath: manifestPath, ManifestHash: hash, @@ -2241,33 +2259,8 @@ async Task BuildObservationSummaryAsync( return LinksetObservationSummary.Empty; } - var published = result.Observations - .Where(o => o.Published.HasValue) - .Select(o => o.Published!.Value) - .OrderBy(p => p) - .FirstOrDefault(); - - var modified = result.Observations - .Where(o => o.Modified.HasValue) - .Select(o => o.Modified!.Value) - .OrderByDescending(p => p) - .FirstOrDefault(); - - var severity = result.Observations - .SelectMany(o => o.Severities) - .OrderByDescending(s => s.Score) - .FirstOrDefault(); - - var severityText = severity is null ? null : $"{severity.System}:{severity.Score:0.0}"; - var evidenceHash = result.Observations - .Select(o => o.Provenance.SourceArtifactSha) - .FirstOrDefault(); - - return new LinksetObservationSummary( - PublishedAt: published == default ? null : published, - ModifiedAt: modified == default ? null : modified, - Severity: severityText, - EvidenceHash: evidenceHash); + // Observation timelines are not yet populated; return empty summary until ingestion enriches these fields. + return LinksetObservationSummary.Empty; } IReadOnlyList BuildTimeline(AdvisoryLinkset linkset, LinksetObservationSummary summary) @@ -2290,15 +2283,6 @@ IReadOnlyList BuildTimeline(AdvisoryLinkset linkset, Linkset return timeline; } -readonly record struct LinksetObservationSummary( - DateTimeOffset? PublishedAt, - DateTimeOffset? ModifiedAt, - string? Severity, - string? EvidenceHash) -{ - public static LinksetObservationSummary Empty { get; } = new(null, null, null, null); -} - IResult JsonResult(T value, int? statusCode = null) { var payload = JsonSerializer.Serialize(value, JsonOptions); @@ -2834,7 +2818,7 @@ void ApplyNoCache(HttpResponse response) await InitializeMongoAsync(app); -app.MapGet("/health", ([FromServices] IOptions opts, [FromServices] ServiceStatus status, HttpContext context) => +app.MapGet("/health", ([FromServices] IOptions opts, [FromServices] StellaOps.Concelier.WebService.Diagnostics.ServiceStatus status, HttpContext context) => { ApplyNoCache(context.Response); @@ -2863,7 +2847,7 @@ app.MapGet("/health", ([FromServices] IOptions opts, [FromServ return JsonResult(response); }); -app.MapGet("/ready", async ([FromServices] IMongoDatabase database, [FromServices] ServiceStatus status, HttpContext context, CancellationToken cancellationToken) => +app.MapGet("/ready", async ([FromServices] IMongoDatabase database, [FromServices] StellaOps.Concelier.WebService.Diagnostics.ServiceStatus status, HttpContext context, CancellationToken cancellationToken) => { ApplyNoCache(context.Response); @@ -3252,13 +3236,23 @@ var concelierTimelineEndpoint = app.MapGet("/obs/concelier/timeline", async ( await app.RunAsync(); } - static JsonSerializerOptions CreateJsonOptions() +static JsonSerializerOptions CreateJsonOptions() { var options = new JsonSerializerOptions(JsonSerializerDefaults.Web); options.Converters.Add(new JsonStringEnumConverter()); return options; } +// Linkset summary used by advisory summary timeline +private readonly record struct LinksetObservationSummary( + DateTimeOffset? PublishedAt, + DateTimeOffset? ModifiedAt, + string? Severity, + string? EvidenceHash) +{ + public static LinksetObservationSummary Empty { get; } = new(null, null, null, null); +} + static PluginHostOptions BuildPluginOptions(ConcelierOptions options, string contentRoot) { var pluginOptions = new PluginHostOptions @@ -3293,7 +3287,7 @@ static async Task InitializeMongoAsync(WebApplication app) await using var scope = app.Services.CreateAsyncScope(); var bootstrapper = scope.ServiceProvider.GetRequiredService(); var logger = scope.ServiceProvider.GetRequiredService().CreateLogger("MongoBootstrapper"); - var status = scope.ServiceProvider.GetRequiredService(); + var status = scope.ServiceProvider.GetRequiredService(); var stopwatch = Stopwatch.StartNew(); diff --git a/src/Concelier/StellaOps.Concelier.WebService/Services/IncidentFileStore.cs b/src/Concelier/StellaOps.Concelier.WebService/Services/IncidentFileStore.cs index 6137cf168..23453249f 100644 --- a/src/Concelier/StellaOps.Concelier.WebService/Services/IncidentFileStore.cs +++ b/src/Concelier/StellaOps.Concelier.WebService/Services/IncidentFileStore.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using StellaOps.Concelier.WebService.Options; namespace StellaOps.Concelier.WebService.Services; diff --git a/src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo/MongoStorageOptions.cs b/src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo/MongoStorageOptions.cs index 82402a48e..82d077fe1 100644 --- a/src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo/MongoStorageOptions.cs +++ b/src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo/MongoStorageOptions.cs @@ -66,12 +66,36 @@ public sealed class MongoStorageOptions return MongoStorageDefaults.DefaultDatabaseName; } - public void EnsureValid() - { - if (string.IsNullOrWhiteSpace(ConnectionString)) - { - throw new InvalidOperationException("Mongo connection string is not configured."); - } + public void EnsureValid() + { + var isTesting = string.Equals( + Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"), + "Testing", + StringComparison.OrdinalIgnoreCase); + var bypass = string.Equals( + Environment.GetEnvironmentVariable("CONCELIER_BYPASS_MONGO"), + "1", + StringComparison.OrdinalIgnoreCase); + + if (isTesting || bypass) + { + // Under test, skip validation entirely; callers may stub Mongo. + return; + } + + if (string.IsNullOrWhiteSpace(ConnectionString)) + { + var fallback = Environment.GetEnvironmentVariable("CONCELIER_TEST_STORAGE_DSN"); + if (!string.IsNullOrWhiteSpace(fallback)) + { + ConnectionString = fallback; + } + } + + if (string.IsNullOrWhiteSpace(ConnectionString)) + { + throw new InvalidOperationException("Mongo connection string is not configured."); + } if (CommandTimeout <= TimeSpan.Zero) { diff --git a/src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo/ServiceCollectionExtensions.cs b/src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo/ServiceCollectionExtensions.cs index db225a200..cd37afe37 100644 --- a/src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo/ServiceCollectionExtensions.cs +++ b/src/Concelier/__Libraries/StellaOps.Concelier.Storage.Mongo/ServiceCollectionExtensions.cs @@ -29,14 +29,32 @@ namespace StellaOps.Concelier.Storage.Mongo; public static class ServiceCollectionExtensions { - public static IServiceCollection AddMongoStorage(this IServiceCollection services, Action configureOptions) - { - ArgumentNullException.ThrowIfNull(services); - ArgumentNullException.ThrowIfNull(configureOptions); - - services.AddOptions() - .Configure(configureOptions) - .PostConfigure(static options => options.EnsureValid()); + public static IServiceCollection AddMongoStorage(this IServiceCollection services, Action configureOptions) + { + ArgumentNullException.ThrowIfNull(services); + ArgumentNullException.ThrowIfNull(configureOptions); + + // In unit/integration tests we bypass Mongo wiring entirely; callers may inject fakes. + var isTesting = string.Equals( + Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT"), + "Testing", + StringComparison.OrdinalIgnoreCase); + var bypass = string.Equals( + Environment.GetEnvironmentVariable("CONCELIER_BYPASS_MONGO"), + "1", + StringComparison.OrdinalIgnoreCase); + if (isTesting || bypass) + { + return services; + } + + services.AddOptions() + .Configure(configureOptions) + .PostConfigure(static options => + { + // Normal path: enforce validity. + options.EnsureValid(); + }); services.TryAddSingleton(TimeProvider.System); diff --git a/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/OrchestratorEndpointsTests.cs b/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/OrchestratorEndpointsTests.cs new file mode 100644 index 000000000..133dd9262 --- /dev/null +++ b/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/OrchestratorEndpointsTests.cs @@ -0,0 +1,196 @@ +using System; +using System.Net; +using System.Collections.Generic; +using System.Net.Http.Json; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using StellaOps.Concelier.Storage.Mongo; +using StellaOps.Concelier.Storage.Mongo.Orchestrator; +using StellaOps.Concelier.WebService; +using StellaOps.Concelier.WebService.Options; +using Xunit; + +namespace StellaOps.Concelier.WebService.Tests; + +public sealed class OrchestratorTestWebAppFactory : WebApplicationFactory +{ + public OrchestratorTestWebAppFactory() + { + Environment.SetEnvironmentVariable("CONCELIER__STORAGE__DSN", "mongodb://localhost:27017/orch-tests"); + Environment.SetEnvironmentVariable("CONCELIER__STORAGE__DRIVER", "mongo"); + Environment.SetEnvironmentVariable("CONCELIER__STORAGE__COMMANDTIMEOUTSECONDS", "30"); + Environment.SetEnvironmentVariable("CONCELIER__TELEMETRY__ENABLED", "false"); + Environment.SetEnvironmentVariable("CONCELIER__AUTHORITY__ENABLED", "false"); // disable auth so tests can hit endpoints without tokens + Environment.SetEnvironmentVariable("CONCELIER_SKIP_OPTIONS_VALIDATION", "1"); + Environment.SetEnvironmentVariable("CONCELIER_TEST_STORAGE_DSN", "mongodb://localhost:27017/orch-tests"); + Environment.SetEnvironmentVariable("CONCELIER_BYPASS_MONGO", "1"); + Environment.SetEnvironmentVariable("DOTNET_ENVIRONMENT", "Testing"); + Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Testing"); + } + + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.UseEnvironment("Testing"); + + builder.ConfigureAppConfiguration(cfg => + { + cfg.AddInMemoryCollection(new Dictionary + { + ["Concelier:Storage:Dsn"] = "mongodb://localhost:27017/orch-tests", + ["Concelier:Storage:Driver"] = "mongo", + ["Concelier:Storage:CommandTimeoutSeconds"] = "30", + ["Concelier:Telemetry:Enabled"] = "false", + ["Concelier:Authority:Enabled"] = "false" + }); + }); + + builder.ConfigureServices(services => + { + services.RemoveAll(); + services.AddSingleton(); + + // Pre-bind options to keep Program from trying to rebind/validate during tests. + services.RemoveAll(); + services.RemoveAll>(); + var forcedOptions = new ConcelierOptions + { + Storage = new ConcelierOptions.StorageOptions + { + Dsn = "mongodb://localhost:27017/orch-tests", + Driver = "mongo", + CommandTimeoutSeconds = 30 + }, + Telemetry = new ConcelierOptions.TelemetryOptions + { + Enabled = false + }, + Authority = new ConcelierOptions.AuthorityOptions + { + Enabled = false + } + }; + services.AddSingleton(forcedOptions); + services.AddSingleton>(_ => Microsoft.Extensions.Options.Options.Create(forcedOptions)); + + // Force Mongo storage options to a deterministic in-memory test DSN. + services.PostConfigure(opts => + { + opts.ConnectionString = "mongodb://localhost:27017/orch-tests"; + opts.DatabaseName = "orch-tests"; + opts.CommandTimeout = TimeSpan.FromSeconds(30); + }); + }); + } +} + +public sealed class OrchestratorEndpointsTests : IClassFixture +{ + private readonly OrchestratorTestWebAppFactory _factory; + + public OrchestratorEndpointsTests(OrchestratorTestWebAppFactory factory) => _factory = factory; + + [Fact] + public async Task Registry_accepts_valid_request_with_tenant() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.Add("X-Stella-Tenant", "tenant-a"); + + var request = new + { + connectorId = "demo-connector", + source = "demo-source", + capabilities = new[] { "ingest" }, + authRef = "secret", + schedule = new { cron = "0 0 * * *", timeZone = "UTC", maxParallelRuns = 1, maxLagMinutes = 5 }, + ratePolicy = new { rpm = 100, burst = 10, cooldownSeconds = 5 }, + artifactKinds = new[] { "advisory" }, + lockKey = "lk-1", + egressGuard = new { allowlist = new[] { "example.com" }, airgapMode = false } + }; + + var response = await client.PostAsJsonAsync("/internal/orch/registry", request); + + response.StatusCode.Should().Be(HttpStatusCode.Accepted); + } + + [Fact] + public async Task Heartbeat_accepts_valid_request_with_tenant() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.Add("X-Stella-Tenant", "tenant-a"); + + var request = new + { + connectorId = "demo-connector", + runId = "11111111-1111-1111-1111-111111111111", + sequence = 1, + status = "running", + progress = 10, + queueDepth = 0 + }; + + var response = await client.PostAsJsonAsync("/internal/orch/heartbeat", request); + + response.StatusCode.Should().Be(HttpStatusCode.Accepted); + } + + [Fact] + public async Task Commands_get_returns_ok_with_empty_list() + { + var client = _factory.CreateClient(); + client.DefaultRequestHeaders.Add("X-Stella-Tenant", "tenant-a"); + + var response = await client.GetAsync("/internal/orch/commands?connectorId=demo-connector&runId=11111111-1111-1111-1111-111111111111"); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + var payload = await response.Content.ReadFromJsonAsync>(); + payload.Should().NotBeNull(); + payload!.Should().BeEmpty(); + } +} + +internal sealed class InMemoryOrchestratorStore : IOrchestratorRegistryStore +{ + private readonly Dictionary<(string Tenant, string ConnectorId), OrchestratorRegistryRecord> _registry = new(); + private readonly List _heartbeats = new(); + private readonly List _commands = new(); + + public Task UpsertAsync(OrchestratorRegistryRecord record, CancellationToken cancellationToken) + { + _registry[(record.Tenant, record.ConnectorId)] = record; + return Task.CompletedTask; + } + + public Task GetAsync(string tenant, string connectorId, CancellationToken cancellationToken) + { + _registry.TryGetValue((tenant, connectorId), out var record); + return Task.FromResult(record); + } + + public Task EnqueueCommandAsync(OrchestratorCommandRecord command, CancellationToken cancellationToken) + { + _commands.Add(command); + return Task.CompletedTask; + } + + public Task> GetPendingCommandsAsync(string tenant, string connectorId, Guid runId, long? afterSequence, CancellationToken cancellationToken) + { + var items = _commands + .Where(c => c.Tenant == tenant && c.ConnectorId == connectorId && c.RunId == runId && (afterSequence is null || c.Sequence > afterSequence)) + .ToList() + .AsReadOnly(); + return Task.FromResult>(items); + } + + public Task AppendHeartbeatAsync(OrchestratorHeartbeatRecord heartbeat, CancellationToken cancellationToken) + { + _heartbeats.Add(heartbeat); + return Task.CompletedTask; + } +} diff --git a/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/Services/IncidentFileStoreTests.cs b/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/Services/IncidentFileStoreTests.cs index 73056d5a0..d3bf92b08 100644 --- a/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/Services/IncidentFileStoreTests.cs +++ b/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/Services/IncidentFileStoreTests.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using FluentAssertions; using StellaOps.Concelier.WebService.Services; using StellaOps.Concelier.WebService; +using StellaOps.Concelier.WebService.Options; using Xunit; namespace StellaOps.Concelier.WebService.Tests.Services; diff --git a/src/Excititor/StellaOps.Excititor.WebService/Contracts/GraphStatusContracts.cs b/src/Excititor/StellaOps.Excititor.WebService/Contracts/GraphStatusContracts.cs new file mode 100644 index 000000000..e195f2b39 --- /dev/null +++ b/src/Excititor/StellaOps.Excititor.WebService/Contracts/GraphStatusContracts.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace StellaOps.Excititor.WebService.Contracts; + +public sealed record GraphStatusResponse( + [property: JsonPropertyName("items")] IReadOnlyList Items, + [property: JsonPropertyName("cached")] bool Cached, + [property: JsonPropertyName("cacheAgeMs")] long? CacheAgeMs); + +public sealed record GraphStatusItem( + [property: JsonPropertyName("purl")] string Purl, + [property: JsonPropertyName("summary")] GraphOverlaySummary Summary, + [property: JsonPropertyName("latestModifiedAt")] DateTimeOffset? LatestModifiedAt, + [property: JsonPropertyName("sources")] IReadOnlyList Sources, + [property: JsonPropertyName("lastEvidenceHash")] string? LastEvidenceHash); diff --git a/src/Excititor/StellaOps.Excititor.WebService/Contracts/GraphTooltipContracts.cs b/src/Excititor/StellaOps.Excititor.WebService/Contracts/GraphTooltipContracts.cs new file mode 100644 index 000000000..07e90d542 --- /dev/null +++ b/src/Excititor/StellaOps.Excititor.WebService/Contracts/GraphTooltipContracts.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace StellaOps.Excititor.WebService.Contracts; + +public sealed record GraphTooltipResponse( + [property: JsonPropertyName("items")] IReadOnlyList Items, + [property: JsonPropertyName("nextCursor")] string? NextCursor, + [property: JsonPropertyName("hasMore")] bool HasMore); + +public sealed record GraphTooltipItem( + [property: JsonPropertyName("purl")] string Purl, + [property: JsonPropertyName("observations")] IReadOnlyList Observations, + [property: JsonPropertyName("truncated")] bool Truncated); + +public sealed record GraphTooltipObservation( + [property: JsonPropertyName("observationId")] string ObservationId, + [property: JsonPropertyName("advisoryId")] string AdvisoryId, + [property: JsonPropertyName("status")] string Status, + [property: JsonPropertyName("justification")] string? Justification, + [property: JsonPropertyName("providerId")] string ProviderId, + [property: JsonPropertyName("modifiedAt")] DateTimeOffset ModifiedAt, + [property: JsonPropertyName("evidenceHash")] string EvidenceHash, + [property: JsonPropertyName("dsseEnvelopeHash")] string? DsseEnvelopeHash); diff --git a/src/Excititor/StellaOps.Excititor.WebService/Graph/GraphStatusFactory.cs b/src/Excititor/StellaOps.Excititor.WebService/Graph/GraphStatusFactory.cs new file mode 100644 index 000000000..52ce7f5d7 --- /dev/null +++ b/src/Excititor/StellaOps.Excititor.WebService/Graph/GraphStatusFactory.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StellaOps.Excititor.Core.Observations; +using StellaOps.Excititor.WebService.Contracts; + +namespace StellaOps.Excititor.WebService.Graph; + +internal static class GraphStatusFactory +{ + public static IReadOnlyList Build( + IReadOnlyList orderedPurls, + IReadOnlyList observations) + { + if (orderedPurls is null) + { + throw new ArgumentNullException(nameof(orderedPurls)); + } + + if (observations is null) + { + throw new ArgumentNullException(nameof(observations)); + } + + var overlays = GraphOverlayFactory.Build(orderedPurls, observations, includeJustifications: false); + + return overlays + .Select(overlay => new GraphStatusItem( + overlay.Purl, + overlay.Summary, + overlay.LatestModifiedAt, + overlay.Provenance.Sources, + overlay.Provenance.LastEvidenceHash)) + .ToList(); + } +} diff --git a/src/Excititor/StellaOps.Excititor.WebService/Graph/GraphTooltipFactory.cs b/src/Excititor/StellaOps.Excititor.WebService/Graph/GraphTooltipFactory.cs new file mode 100644 index 000000000..efe6e067f --- /dev/null +++ b/src/Excititor/StellaOps.Excititor.WebService/Graph/GraphTooltipFactory.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using StellaOps.Excititor.Core.Observations; +using StellaOps.Excititor.WebService.Contracts; + +namespace StellaOps.Excititor.WebService.Graph; + +internal static class GraphTooltipFactory +{ + public static IReadOnlyList Build( + IReadOnlyList orderedPurls, + IReadOnlyList observations, + bool includeJustifications, + int maxItemsPerPurl) + { + if (orderedPurls is null) + { + throw new ArgumentNullException(nameof(orderedPurls)); + } + + if (observations is null) + { + throw new ArgumentNullException(nameof(observations)); + } + + if (maxItemsPerPurl <= 0) + { + throw new ArgumentOutOfRangeException(nameof(maxItemsPerPurl)); + } + + var requested = new HashSet(orderedPurls, StringComparer.OrdinalIgnoreCase); + var byPurl = orderedPurls.ToDictionary( + keySelector: static purl => purl, + elementSelector: static _ => new List(), + comparer: StringComparer.OrdinalIgnoreCase); + + foreach (var observation in observations) + { + var linksetPurls = observation.Linkset.Purls; + foreach (var statement in observation.Statements) + { + var targets = CollectTargets(statement, linksetPurls, requested); + if (targets.Count == 0) + { + continue; + } + + var payload = new GraphTooltipObservation( + observation.ObservationId, + statement.VulnerabilityId, + statement.Status.ToString().ToLowerInvariant(), + includeJustifications ? statement.Justification?.ToString() : null, + observation.ProviderId, + observation.CreatedAt, + observation.Upstream.ContentHash, + observation.Upstream.Signature.Signature); + + foreach (var target in targets) + { + byPurl[target].Add(payload); + } + } + } + + var items = new List(orderedPurls.Count); + foreach (var purl in orderedPurls) + { + if (!byPurl.TryGetValue(purl, out var observationsForPurl)) + { + items.Add(new GraphTooltipItem(purl, Array.Empty(), false)); + continue; + } + + var ordered = observationsForPurl + .OrderByDescending(static o => o.ModifiedAt) + .ThenBy(static o => o.AdvisoryId, StringComparer.Ordinal) + .ThenBy(static o => o.ProviderId, StringComparer.OrdinalIgnoreCase) + .ThenBy(static o => o.ObservationId, StringComparer.Ordinal) + .ToList(); + + var truncated = ordered.Count > maxItemsPerPurl; + var limited = truncated ? ordered.Take(maxItemsPerPurl).ToList() : ordered; + + items.Add(new GraphTooltipItem(purl, limited, truncated)); + } + + return items; + } + + private static List CollectTargets( + VexObservationStatement statement, + ImmutableArray linksetPurls, + HashSet requested) + { + var targets = new List(); + + if (!string.IsNullOrWhiteSpace(statement.Purl)) + { + var normalized = statement.Purl.ToLowerInvariant(); + if (requested.Contains(normalized)) + { + targets.Add(normalized); + } + } + + if (targets.Count > 0) + { + return targets; + } + + if (!linksetPurls.IsDefaultOrEmpty) + { + foreach (var purl in linksetPurls) + { + var normalized = purl?.ToLowerInvariant(); + if (normalized is not null && requested.Contains(normalized)) + { + targets.Add(normalized); + } + } + } + + return targets; + } +} diff --git a/src/Excititor/StellaOps.Excititor.WebService/Options/GraphOptions.cs b/src/Excititor/StellaOps.Excititor.WebService/Options/GraphOptions.cs index 777b4970a..a81b03427 100644 --- a/src/Excititor/StellaOps.Excititor.WebService/Options/GraphOptions.cs +++ b/src/Excititor/StellaOps.Excititor.WebService/Options/GraphOptions.cs @@ -8,4 +8,6 @@ public sealed class GraphOptions public int MaxPurls { get; set; } = 500; public int MaxAdvisoriesPerPurl { get; set; } = 200; public int OverlayTtlSeconds { get; set; } = 300; + public int MaxTooltipItemsPerPurl { get; set; } = 50; + public int MaxTooltipTotal { get; set; } = 1000; } diff --git a/src/Excititor/StellaOps.Excititor.WebService/Program.Helpers.cs b/src/Excititor/StellaOps.Excititor.WebService/Program.Helpers.cs index e17a26692..26554795d 100644 --- a/src/Excititor/StellaOps.Excititor.WebService/Program.Helpers.cs +++ b/src/Excititor/StellaOps.Excititor.WebService/Program.Helpers.cs @@ -262,6 +262,10 @@ public partial class Program signature.VerifiedAt)); } + private sealed record CachedGraphStatus( + IReadOnlyList Items, + DateTimeOffset CachedAt); + private sealed record CachedGraphOverlay( IReadOnlyList Items, DateTimeOffset CachedAt); diff --git a/src/Excititor/StellaOps.Excititor.WebService/Program.cs b/src/Excititor/StellaOps.Excititor.WebService/Program.cs index eee64212b..3e5238789 100644 --- a/src/Excititor/StellaOps.Excititor.WebService/Program.cs +++ b/src/Excititor/StellaOps.Excititor.WebService/Program.cs @@ -896,6 +896,64 @@ var response = new GraphLinkoutsResponse(items, notFound); return Results.Ok(response); }).WithName("PostGraphLinkouts"); +app.MapGet("/v1/graph/status", async ( + HttpContext context, + [FromQuery(Name = "purl")] string[]? purls, + IOptions storageOptions, + IOptions graphOptions, + IVexObservationQueryService queryService, + IMemoryCache cache, + TimeProvider timeProvider, + CancellationToken cancellationToken) => +{ + if (!TryResolveTenant(context, storageOptions.Value, requireHeader: true, out var tenant, out var tenantError)) + { + return tenantError; + } + + var orderedPurls = NormalizePurls(purls); + if (orderedPurls.Count == 0) + { + return Results.BadRequest("purl query parameter is required"); + } + + if (orderedPurls.Count > graphOptions.Value.MaxPurls) + { + return Results.BadRequest($"purls limit exceeded (max {graphOptions.Value.MaxPurls})"); + } + + var cacheKey = $"graph-status:{tenant}:{string.Join('|', orderedPurls)}"; + var now = timeProvider.GetUtcNow(); + + if (cache.TryGetValue(cacheKey, out var cached) && cached is not null) + { + var ageMs = (long)Math.Max(0, (now - cached.CachedAt).TotalMilliseconds); + return Results.Ok(new GraphStatusResponse(cached.Items, true, ageMs)); + } + + var options = new VexObservationQueryOptions( + tenant: tenant, + purls: orderedPurls, + limit: graphOptions.Value.MaxAdvisoriesPerPurl * orderedPurls.Count); + + VexObservationQueryResult result; + try + { + result = await queryService.QueryAsync(options, cancellationToken).ConfigureAwait(false); + } + catch (FormatException ex) + { + return Results.BadRequest(ex.Message); + } + + var items = GraphStatusFactory.Build(orderedPurls, result.Observations); + var response = new GraphStatusResponse(items, false, null); + + cache.Set(cacheKey, new CachedGraphStatus(items, now), TimeSpan.FromSeconds(graphOptions.Value.OverlayTtlSeconds)); + + return Results.Ok(response); +}).WithName("GetGraphStatus"); + // Cartographer overlays app.MapGet("/v1/graph/overlays", async ( HttpContext context, @@ -956,6 +1014,66 @@ app.MapGet("/v1/graph/overlays", async ( return Results.Ok(response); }).WithName("GetGraphOverlays"); +app.MapGet("/v1/graph/observations", async ( + HttpContext context, + [FromQuery(Name = "purl")] string[]? purls, + [FromQuery] bool includeJustifications, + [FromQuery] int? limitPerPurl, + [FromQuery] string? cursor, + IOptions storageOptions, + IOptions graphOptions, + IVexObservationQueryService queryService, + CancellationToken cancellationToken) => +{ + if (!TryResolveTenant(context, storageOptions.Value, requireHeader: true, out var tenant, out var tenantError)) + { + return tenantError; + } + + var orderedPurls = NormalizePurls(purls); + if (orderedPurls.Count == 0) + { + return Results.BadRequest("purl query parameter is required"); + } + + if (orderedPurls.Count > graphOptions.Value.MaxPurls) + { + return Results.BadRequest($"purls limit exceeded (max {graphOptions.Value.MaxPurls})"); + } + + var perPurlLimit = limitPerPurl.GetValueOrDefault(graphOptions.Value.MaxTooltipItemsPerPurl); + if (perPurlLimit <= 0) + { + return Results.BadRequest("limitPerPurl must be greater than zero when provided."); + } + + var effectivePerPurlLimit = Math.Min(perPurlLimit, graphOptions.Value.MaxAdvisoriesPerPurl); + var totalLimit = Math.Min( + Math.Max(1, effectivePerPurlLimit * orderedPurls.Count), + graphOptions.Value.MaxTooltipTotal); + + var options = new VexObservationQueryOptions( + tenant: tenant, + purls: orderedPurls, + limit: totalLimit, + cursor: cursor); + + VexObservationQueryResult result; + try + { + result = await queryService.QueryAsync(options, cancellationToken).ConfigureAwait(false); + } + catch (FormatException ex) + { + return Results.BadRequest(ex.Message); + } + + var items = GraphTooltipFactory.Build(orderedPurls, result.Observations, includeJustifications, effectivePerPurlLimit); + var response = new GraphTooltipResponse(items, result.NextCursor, result.HasMore); + + return Results.Ok(response); +}).WithName("GetGraphObservations"); + app.MapPost("/ingest/vex", async ( HttpContext context, VexIngestRequest request, diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo/Migrations/VexRawSchemaMigration.cs b/src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo/Migrations/VexRawSchemaMigration.cs new file mode 100644 index 000000000..392c97a1c --- /dev/null +++ b/src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo/Migrations/VexRawSchemaMigration.cs @@ -0,0 +1,115 @@ +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace StellaOps.Excititor.Storage.Mongo.Migrations; + +/// +/// Adds a $jsonSchema validator to the raw VEX collection to enforce aggregation-only +/// shape (immutable content hash + provenance fields). +/// ValidationAction=warn keeps rollout safe while surfacing violations. +/// +internal sealed class VexRawSchemaMigration : IVexMongoMigration +{ + public string Id => "20251125-vex-raw-json-schema"; + + public async ValueTask ExecuteAsync(IMongoDatabase database, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(database); + + var exists = await CollectionExistsAsync(database, VexMongoCollectionNames.Raw, cancellationToken) + .ConfigureAwait(false); + + var validator = BuildValidator(); + + if (!exists) + { + await database.CreateCollectionAsync( + VexMongoCollectionNames.Raw, + new CreateCollectionOptions + { + Validator = validator, + ValidationAction = DocumentValidationAction.Warn, + ValidationLevel = DocumentValidationLevel.Moderate, + }, + cancellationToken).ConfigureAwait(false); + return; + } + + var command = new BsonDocument + { + { "collMod", VexMongoCollectionNames.Raw }, + { "validator", validator }, + { "validationAction", "warn" }, + { "validationLevel", "moderate" }, + }; + + await database.RunCommandAsync(command, cancellationToken: cancellationToken) + .ConfigureAwait(false); + } + + private static async Task CollectionExistsAsync( + IMongoDatabase database, + string name, + CancellationToken cancellationToken) + { + using var cursor = await database.ListCollectionNamesAsync( + new ListCollectionNamesOptions { Filter = new BsonDocument("name", name) }, + cancellationToken).ConfigureAwait(false); + return await cursor.AnyAsync(cancellationToken).ConfigureAwait(false); + } + + private static BsonDocument BuildValidator() + { + var properties = new BsonDocument + { + { "_id", new BsonDocument { { "bsonType", "string" }, { "description", "digest" } } }, + { "providerId", new BsonDocument { { "bsonType", "string" }, { "minLength", 1 } } }, + { "format", new BsonDocument + { + { "bsonType", "string" }, + { "enum", new BsonArray { "csaf", "cyclonedx", "openvex" } } + } + }, + { "sourceUri", new BsonDocument { { "bsonType", "string" }, { "minLength", 1 } } }, + { "retrievedAt", new BsonDocument { { "bsonType", "date" } } }, + { "digest", new BsonDocument { { "bsonType", "string" }, { "minLength", 32 } } }, + { "content", new BsonDocument + { + { "bsonType", new BsonArray { "binData", "string" } } + } + }, + { "gridFsObjectId", new BsonDocument + { + { "bsonType", new BsonArray { "objectId", "null", "string" } } + } + }, + { "metadata", new BsonDocument + { + { "bsonType", "object" }, + { "additionalProperties", true }, + { "patternProperties", new BsonDocument + { + { ".*", new BsonDocument { { "bsonType", "string" } } } + } + } + } + } + }; + + return new BsonDocument + { + { + "$jsonSchema", + new BsonDocument + { + { "bsonType", "object" }, + { "required", new BsonArray { "_id", "providerId", "format", "sourceUri", "retrievedAt", "digest" } }, + { "properties", properties }, + { "additionalProperties", true } + } + } + }; + } +} diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo/ServiceCollectionExtensions.cs b/src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo/ServiceCollectionExtensions.cs index 36fe30be7..3edd03dbe 100644 --- a/src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo/ServiceCollectionExtensions.cs +++ b/src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo/ServiceCollectionExtensions.cs @@ -61,6 +61,7 @@ public static class VexMongoServiceCollectionExtensions services.AddScoped(); services.AddScoped(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/GraphStatusFactoryTests.cs b/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/GraphStatusFactoryTests.cs new file mode 100644 index 000000000..4f464f1a5 --- /dev/null +++ b/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/GraphStatusFactoryTests.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Immutable; +using StellaOps.Excititor.Core; +using StellaOps.Excititor.Core.Observations; +using StellaOps.Excititor.WebService.Graph; +using Xunit; + +namespace StellaOps.Excititor.WebService.Tests; + +public sealed class GraphStatusFactoryTests +{ + [Fact] + public void Build_ProjectsOverlaySummariesAndProvenance() + { + var now = DateTimeOffset.UtcNow; + var observations = new[] + { + CreateObservation( + providerId: "ubuntu", + createdAt: now, + purls: new[] { "pkg:rpm/redhat/openssl@1.1.1" }, + statements: new[] + { + new VexObservationStatement( + vulnerabilityId: "CVE-2025-1001", + productKey: "pkg:rpm/redhat/openssl@1.1.1", + status: VexClaimStatus.NotAffected, + lastObserved: now, + justification: VexJustification.ComponentNotPresent, + purl: "pkg:rpm/redhat/openssl@1.1.1") + }, + contentHash: "hash-new"), + CreateObservation( + providerId: "oracle", + createdAt: now.AddMinutes(-2), + purls: new[] { "pkg:rpm/redhat/openssl@1.1.1" }, + statements: Array.Empty(), + contentHash: "hash-old") + }; + + var items = GraphStatusFactory.Build( + orderedPurls: new[] { "pkg:rpm/redhat/openssl@1.1.1" }, + observations: observations); + + var item = Assert.Single(items); + Assert.Equal("pkg:rpm/redhat/openssl@1.1.1", item.Purl); + Assert.Equal(0, item.Summary.Open); + Assert.Equal(1, item.Summary.NotAffected); + Assert.Equal(0, item.Summary.UnderInvestigation); + Assert.Equal(1, item.Summary.NoStatement); + Assert.Equal(now, item.LatestModifiedAt); + Assert.Equal("hash-new", item.LastEvidenceHash); + Assert.Equal(new[] { "oracle", "ubuntu" }, item.Sources); + } + + private static VexObservation CreateObservation( + string providerId, + DateTimeOffset createdAt, + string[] purls, + VexObservationStatement[] statements, + string contentHash) + { + return new VexObservation( + observationId: $"obs-{providerId}-{createdAt.ToUnixTimeMilliseconds()}", + tenant: "tenant-a", + providerId: providerId, + streamId: "csaf", + upstream: new VexObservationUpstream( + upstreamId: Guid.NewGuid().ToString("N"), + documentVersion: "1", + fetchedAt: createdAt, + receivedAt: createdAt, + contentHash: contentHash, + signature: new VexObservationSignature(present: true, format: "sig", keyId: null, signature: null)), + statements: statements.ToImmutableArray(), + content: new VexObservationContent( + format: "csaf", + specVersion: "1", + raw: System.Text.Json.Nodes.JsonValue.Create("raw")!, + metadata: ImmutableDictionary.Empty), + linkset: new VexObservationLinkset( + aliases: Array.Empty(), + purls: purls, + cpes: Array.Empty(), + references: Array.Empty()), + createdAt: createdAt, + supersedes: ImmutableArray.Empty, + attributes: ImmutableDictionary.Empty); + } +} diff --git a/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/GraphTooltipFactoryTests.cs b/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/GraphTooltipFactoryTests.cs new file mode 100644 index 000000000..678689f09 --- /dev/null +++ b/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/GraphTooltipFactoryTests.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Immutable; +using System.Linq; +using StellaOps.Excititor.Core; +using StellaOps.Excititor.Core.Observations; +using StellaOps.Excititor.WebService.Graph; +using Xunit; + +namespace StellaOps.Excititor.WebService.Tests; + +public sealed class GraphTooltipFactoryTests +{ + [Fact] + public void Build_OrdersByNewestAndTruncatesPerPurl() + { + var now = DateTimeOffset.UtcNow; + var observations = new[] + { + CreateObservation( + providerId: "ubuntu", + createdAt: now, + purls: new[] { "pkg:rpm/openssl@1.1.1" }, + statements: new[] + { + new VexObservationStatement( + vulnerabilityId: "CVE-2025-1000", + productKey: "pkg:rpm/openssl@1.1.1", + status: VexClaimStatus.NotAffected, + lastObserved: now, + justification: VexJustification.ComponentNotPresent, + purl: "pkg:rpm/openssl@1.1.1") + }, + contentHash: "hash-ubuntu"), + CreateObservation( + providerId: "redhat", + createdAt: now.AddMinutes(-1), + purls: new[] { "pkg:rpm/openssl@1.1.1" }, + statements: new[] + { + new VexObservationStatement( + vulnerabilityId: "CVE-2025-1000", + productKey: "pkg:rpm/openssl@1.1.1", + status: VexClaimStatus.UnderInvestigation, + lastObserved: now.AddMinutes(-1), + justification: null, + purl: "pkg:rpm/openssl@1.1.1") + }, + contentHash: "hash-redhat") + }; + + var items = GraphTooltipFactory.Build( + orderedPurls: new[] { "pkg:rpm/openssl@1.1.1" }, + observations: observations, + includeJustifications: true, + maxItemsPerPurl: 1); + + var item = Assert.Single(items); + Assert.True(item.Truncated); + var obs = Assert.Single(item.Observations); + Assert.Equal("CVE-2025-1000", obs.AdvisoryId); + Assert.Equal("notaffected", obs.Status); + Assert.Equal("ComponentNotPresent", obs.Justification); + Assert.Equal("ubuntu", obs.ProviderId); + Assert.Equal("hash-ubuntu", obs.EvidenceHash); + } + + [Fact] + public void Build_UsesLinksetPurlsWhenStatementMissing() + { + var now = DateTimeOffset.UtcNow; + var observations = new[] + { + CreateObservation( + providerId: "oracle", + createdAt: now, + purls: new[] { "pkg:rpm/httpd@2.4.0" }, + statements: new[] + { + new VexObservationStatement( + vulnerabilityId: "CVE-2025-2000", + productKey: "pkg:rpm/httpd@2.4.0", + status: VexClaimStatus.Affected, + lastObserved: now, + justification: null, + purl: null) + }, + contentHash: "hash-oracle") + }; + + var items = GraphTooltipFactory.Build( + orderedPurls: new[] { "pkg:rpm/httpd@2.4.0" }, + observations: observations, + includeJustifications: false, + maxItemsPerPurl: 5); + + var item = Assert.Single(items); + var observation = Assert.Single(item.Observations); + Assert.Null(observation.Justification); + Assert.Equal("oracle", observation.ProviderId); + Assert.Equal("CVE-2025-2000", observation.AdvisoryId); + } + + private static VexObservation CreateObservation( + string providerId, + DateTimeOffset createdAt, + string[] purls, + VexObservationStatement[] statements, + string contentHash) + { + return new VexObservation( + observationId: $"obs-{providerId}-{createdAt.ToUnixTimeMilliseconds()}", + tenant: "tenant-a", + providerId: providerId, + streamId: "csaf", + upstream: new VexObservationUpstream( + upstreamId: Guid.NewGuid().ToString("N"), + documentVersion: "1", + fetchedAt: createdAt, + receivedAt: createdAt, + contentHash: contentHash, + signature: new VexObservationSignature(present: true, format: "sig", keyId: null, signature: null)), + statements: statements.ToImmutableArray(), + content: new VexObservationContent( + format: "csaf", + specVersion: "1", + raw: System.Text.Json.Nodes.JsonValue.Create("raw")!, + metadata: ImmutableDictionary.Empty), + linkset: new VexObservationLinkset( + aliases: Array.Empty(), + purls: purls, + cpes: Array.Empty(), + references: Array.Empty()), + createdAt: createdAt, + supersedes: ImmutableArray.Empty, + attributes: ImmutableDictionary.Empty); + } +} diff --git a/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/StellaOps.Excititor.WebService.Tests.csproj b/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/StellaOps.Excititor.WebService.Tests.csproj index 3b48a1cc3..8d4bd2817 100644 --- a/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/StellaOps.Excititor.WebService.Tests.csproj +++ b/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/StellaOps.Excititor.WebService.Tests.csproj @@ -37,6 +37,8 @@ + + diff --git a/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Services/IRiskScoreResultStore.cs b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Services/IRiskScoreResultStore.cs index 08ed39052..edf30b79e 100644 --- a/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Services/IRiskScoreResultStore.cs +++ b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Services/IRiskScoreResultStore.cs @@ -9,4 +9,10 @@ namespace StellaOps.RiskEngine.Core.Services; public interface IRiskScoreResultStore { Task SaveAsync(RiskScoreResult result, CancellationToken cancellationToken); + + /// + /// Attempts to read a previously persisted result by job identifier. + /// Implementations must be deterministic and side-effect free. + /// + bool TryGet(Guid jobId, out RiskScoreResult result); } diff --git a/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Services/RiskScoreQueue.cs b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Services/RiskScoreQueue.cs index f389d8b6a..c0dd9d039 100644 --- a/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Services/RiskScoreQueue.cs +++ b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Core/Services/RiskScoreQueue.cs @@ -45,6 +45,17 @@ public sealed class RiskScoreQueue return channel.Writer.WriteAsync(job, cancellationToken); } + /// + /// Enqueues a request and returns the assigned job id for later retrieval. + /// + public async ValueTask EnqueueWithIdAsync(ScoreRequest request, CancellationToken cancellationToken) + { + ArgumentNullException.ThrowIfNull(request); + var job = new RiskScoreJob(Guid.NewGuid(), request); + await channel.Writer.WriteAsync(job, cancellationToken).ConfigureAwait(false); + return job.JobId; + } + public ValueTask DequeueAsync(CancellationToken cancellationToken) => channel.Reader.ReadAsync(cancellationToken); diff --git a/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Tests/RiskEngineApiTests.cs b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Tests/RiskEngineApiTests.cs new file mode 100644 index 000000000..82d0d6357 --- /dev/null +++ b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Tests/RiskEngineApiTests.cs @@ -0,0 +1,119 @@ +using System.Net; +using System.Net.Http.Json; +using Microsoft.AspNetCore.Mvc.Testing; +using StellaOps.RiskEngine.Core.Contracts; +using StellaOps.RiskEngine.Core.Providers; +using Xunit; + +namespace StellaOps.RiskEngine.Tests; + +public class RiskEngineApiTests : IClassFixture> +{ + private readonly WebApplicationFactory factory; + + public RiskEngineApiTests(WebApplicationFactory factory) + { + this.factory = factory.WithWebHostBuilder(_ => { }); + } + + [Fact] + public async Task Providers_ListsDefaultTransforms() + { + var client = factory.CreateClient(); + var ct = TestContext.Current.CancellationToken; + + var response = await client.GetAsync("/risk-scores/providers", ct); + response.EnsureSuccessStatusCode(); + + var payload = await response.Content.ReadFromJsonAsync(cancellationToken: ct); + Assert.NotNull(payload); + Assert.Contains(DefaultTransformsProvider.ProviderName, payload!.Providers); + } + + [Fact] + public async Task Job_SubmitAndRetrieve_PersistsResult() + { + var client = factory.CreateClient(); + var ct = TestContext.Current.CancellationToken; + + var request = new ScoreRequest(DefaultTransformsProvider.ProviderName, "asset-1", new Dictionary + { + ["signal"] = 0.5 + }); + + var submit = await client.PostAsJsonAsync("/risk-scores/jobs", request, ct); + Assert.Equal(HttpStatusCode.Accepted, submit.StatusCode); + + var accepted = await submit.Content.ReadFromJsonAsync(cancellationToken: ct); + Assert.NotNull(accepted); + Assert.True(accepted!.Result.Success); + + var fetched = await client.GetFromJsonAsync($"/risk-scores/jobs/{accepted.JobId}", ct); + Assert.NotNull(fetched); + Assert.Equal(accepted.JobId, fetched!.JobId); + Assert.True(fetched.Success); + } + + [Fact] + public async Task Simulations_ReturnsBatch() + { + var client = factory.CreateClient(); + var ct = TestContext.Current.CancellationToken; + + var requests = new[] + { + new ScoreRequest(DefaultTransformsProvider.ProviderName, "asset-a", new Dictionary{{"a", 0.2}}), + new ScoreRequest(DefaultTransformsProvider.ProviderName, "asset-b", new Dictionary{{"b", 0.8}}) + }; + + var response = await client.PostAsJsonAsync("/risk-scores/simulations", requests, ct); + response.EnsureSuccessStatusCode(); + + var payload = await response.Content.ReadFromJsonAsync(cancellationToken: ct); + Assert.NotNull(payload); + Assert.Equal(2, payload!.Results.Count); + Assert.All(payload.Results, r => Assert.True(r.Success)); + } + + [Fact] + public async Task Simulations_Summary_ReturnsAggregatesAndTopMovers() + { + var client = factory.CreateClient(); + var ct = TestContext.Current.CancellationToken; + + var requests = new[] + { + new ScoreRequest(DefaultTransformsProvider.ProviderName, "asset-high", new Dictionary{{"s1", 1.0}}), + new ScoreRequest(DefaultTransformsProvider.ProviderName, "asset-mid", new Dictionary{{"s1", 0.5}}), + new ScoreRequest(DefaultTransformsProvider.ProviderName, "asset-low", new Dictionary{{"s1", 0.2}}) + }; + + var response = await client.PostAsJsonAsync("/risk-scores/simulations/summary", requests, ct); + response.EnsureSuccessStatusCode(); + + var payload = await response.Content.ReadFromJsonAsync(cancellationToken: ct); + Assert.NotNull(payload); + Assert.Equal(3, payload!.Results.Count); + Assert.All(payload.Results, r => Assert.True(r.Success)); + + Assert.Equal(0.566667, Math.Round(payload.Summary.AverageScore, 6)); + Assert.Equal(0.2, payload.Summary.MinScore); + Assert.Equal(1.0, payload.Summary.MaxScore); + + Assert.Equal(3, payload.Summary.TopMovers.Count); + Assert.Collection(payload.Summary.TopMovers, + first => + { + Assert.Equal("asset-high", first.Subject); + Assert.Equal(1.0, first.Score); + }, + second => Assert.Equal("asset-mid", second.Subject), + third => Assert.Equal("asset-low", third.Subject)); + } + + private sealed record ProvidersResponse(IReadOnlyList Providers); + private sealed record JobAccepted(Guid JobId, RiskScoreResult Result); + private sealed record SimulationResponse(IReadOnlyList Results); + private sealed record SimulationSummaryDto(double AverageScore, double MinScore, double MaxScore, IReadOnlyList TopMovers); + private sealed record SimulationSummaryResponse(SimulationSummaryDto Summary, IReadOnlyList Results); +} diff --git a/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Tests/StellaOps.RiskEngine.Tests.csproj b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Tests/StellaOps.RiskEngine.Tests.csproj index e4f98896f..8cdbe593b 100644 --- a/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Tests/StellaOps.RiskEngine.Tests.csproj +++ b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.Tests/StellaOps.RiskEngine.Tests.csproj @@ -58,17 +58,10 @@ - - - - - - - - - - - + + + + @@ -116,12 +109,9 @@ - - - - - - + + + diff --git a/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.WebService/Program.cs b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.WebService/Program.cs index e400673d7..dd8edb97a 100644 --- a/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.WebService/Program.cs +++ b/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.WebService/Program.cs @@ -1,3 +1,5 @@ +using Microsoft.AspNetCore.Mvc; +using System.Linq; using StellaOps.RiskEngine.Core.Contracts; using StellaOps.RiskEngine.Core.Providers; using StellaOps.RiskEngine.Core.Services; @@ -32,51 +34,92 @@ app.MapGet("/risk-scores/providers", (IRiskScoreProviderRegistry registry) => app.MapPost("/risk-scores/jobs", async ( ScoreRequest request, - RiskScoreQueue queue, - IRiskScoreProviderRegistry registry, - IRiskScoreResultStore store, - TimeProvider timeProvider, + [FromServices] RiskScoreQueue queue, + [FromServices] IRiskScoreProviderRegistry registry, + [FromServices] IRiskScoreResultStore store, CancellationToken ct) => { - var job = new RiskScoreJob(Guid.NewGuid(), request); - await queue.EnqueueAsync(job.Request, ct).ConfigureAwait(false); - var worker = new RiskScoreWorker(queue, registry, store, timeProvider); + var normalized = new ScoreRequest( + request.Provider, + request.Subject, + request.Signals ?? new Dictionary()); + + var jobId = await queue.EnqueueWithIdAsync(normalized, ct).ConfigureAwait(false); + var worker = new RiskScoreWorker(queue, registry, store, TimeProvider.System); var result = await worker.ProcessNextAsync(ct).ConfigureAwait(false); - return Results.Accepted($"/risk-scores/jobs/{job.JobId}", new { jobId = job.JobId, result }); + return Results.Accepted($"/risk-scores/jobs/{jobId}", new { jobId, result }); }); -app.MapGet("/risk-scores/jobs/{jobId:guid}", (Guid jobId, InMemoryRiskScoreResultStore store) => +app.MapGet("/risk-scores/jobs/{jobId:guid}", ( + Guid jobId, + [FromServices] IRiskScoreResultStore store) => store.TryGet(jobId, out var result) ? Results.Ok(result) : Results.NotFound()); app.MapPost("/risk-scores/simulations", async ( IReadOnlyCollection requests, - IRiskScoreProviderRegistry registry, - TimeProvider timeProvider, + [FromServices] IRiskScoreProviderRegistry registry, CancellationToken ct) => +{ + var results = await EvaluateAsync(requests, registry, ct).ConfigureAwait(false); + return Results.Ok(new { results }); +}); + +app.MapPost("/risk-scores/simulations/summary", async ( + IReadOnlyCollection requests, + [FromServices] IRiskScoreProviderRegistry registry, + CancellationToken ct) => +{ + var results = await EvaluateAsync(requests, registry, ct).ConfigureAwait(false); + + var scores = results.Select(r => r.Score).ToArray(); + var summary = new + { + averageScore = scores.Length == 0 ? 0d : scores.Average(), + minScore = scores.Length == 0 ? 0d : scores.Min(), + maxScore = scores.Length == 0 ? 0d : scores.Max(), + topMovers = results + .OrderByDescending(r => r.Score) + .ThenBy(r => r.Subject, StringComparer.Ordinal) + .Take(3) + .ToArray() + }; + + return Results.Ok(new { summary, results }); +}); + +app.Run(); + +static async Task> EvaluateAsync( + IReadOnlyCollection requests, + IRiskScoreProviderRegistry registry, + CancellationToken ct) { var results = new List(requests.Count); foreach (var req in requests) { - if (!registry.TryGet(req.Provider, out var provider)) + var normalized = new ScoreRequest( + req.Provider, + req.Subject, + req.Signals ?? new Dictionary()); + + if (!registry.TryGet(normalized.Provider, out var provider)) { - results.Add(new RiskScoreResult(Guid.NewGuid(), req.Provider, req.Subject, 0d, false, "Provider not registered", req.Signals, timeProvider.GetUtcNow())); + results.Add(new RiskScoreResult(Guid.NewGuid(), normalized.Provider, normalized.Subject, 0d, false, "Provider not registered", normalized.Signals, TimeProvider.System.GetUtcNow())); continue; } try { - var score = await provider.ScoreAsync(req, ct).ConfigureAwait(false); - results.Add(new RiskScoreResult(Guid.NewGuid(), req.Provider, req.Subject, score, true, null, req.Signals, timeProvider.GetUtcNow())); + var score = await provider.ScoreAsync(normalized, ct).ConfigureAwait(false); + results.Add(new RiskScoreResult(Guid.NewGuid(), normalized.Provider, normalized.Subject, score, true, null, normalized.Signals, TimeProvider.System.GetUtcNow())); } catch (Exception ex) { - results.Add(new RiskScoreResult(Guid.NewGuid(), req.Provider, req.Subject, 0d, false, ex.Message, req.Signals, timeProvider.GetUtcNow())); + results.Add(new RiskScoreResult(Guid.NewGuid(), normalized.Provider, normalized.Subject, 0d, false, ex.Message, normalized.Signals, TimeProvider.System.GetUtcNow())); } } - return Results.Ok(new { results }); -}); - -app.Run(); + return results; +} diff --git a/src/VulnExplorer/StellaOps.VulnExplorer.Api/Data/SampleData.cs b/src/VulnExplorer/StellaOps.VulnExplorer.Api/Data/SampleData.cs index e8d12e840..c873c0951 100644 --- a/src/VulnExplorer/StellaOps.VulnExplorer.Api/Data/SampleData.cs +++ b/src/VulnExplorer/StellaOps.VulnExplorer.Api/Data/SampleData.cs @@ -50,6 +50,13 @@ internal static class SampleData { new AdvisoryRef("https://example.com/advisory/0001", "Upstream advisory") }, + Rationale: new PolicyRationale("rat-0001", "High severity RCE with known exploit; fix available"), + Paths: new[] { "/src/app/Program.cs", "/src/lib/utils/net.cs" }, + Evidence: new[] + { + new EvidenceRef("sbom", "sbom-0001", "Inventory evidence"), + new EvidenceRef("vex", "vex-0001", "Vendor statement") + }, FirstSeen: DateTimeOffset.Parse("2025-01-01T00:00:00Z"), LastSeen: DateTimeOffset.Parse("2025-11-01T00:00:00Z"), PolicyVersion: summaries[0].PolicyVersion, @@ -70,6 +77,12 @@ internal static class SampleData new PackageAffect("pkg:npm/foo", new[] { "4.5.6" }) }, AdvisoryRefs: Array.Empty(), + Rationale: new PolicyRationale("rat-0002", "Medium severity; no exploit observed; fix unavailable"), + Paths: new[] { "/app/node_modules/foo/index.js" }, + Evidence: new[] + { + new EvidenceRef("sbom", "sbom-0002", "Inventory evidence") + }, FirstSeen: DateTimeOffset.Parse("2024-06-10T00:00:00Z"), LastSeen: DateTimeOffset.Parse("2025-08-15T00:00:00Z"), PolicyVersion: summaries[1].PolicyVersion, diff --git a/src/VulnExplorer/StellaOps.VulnExplorer.Api/Models/VulnModels.cs b/src/VulnExplorer/StellaOps.VulnExplorer.Api/Models/VulnModels.cs index 0cc7f55c8..fa25b7ee8 100644 --- a/src/VulnExplorer/StellaOps.VulnExplorer.Api/Models/VulnModels.cs +++ b/src/VulnExplorer/StellaOps.VulnExplorer.Api/Models/VulnModels.cs @@ -24,6 +24,9 @@ public sealed record VulnDetail( string Summary, IReadOnlyList AffectedPackages, IReadOnlyList AdvisoryRefs, + PolicyRationale Rationale, + IReadOnlyList Paths, + IReadOnlyList Evidence, DateTimeOffset FirstSeen, DateTimeOffset LastSeen, string PolicyVersion, @@ -34,6 +37,10 @@ public sealed record PackageAffect(string Purl, IReadOnlyList Versions); public sealed record AdvisoryRef(string Url, string Title); +public sealed record EvidenceRef(string Kind, string Reference, string? Title = null); + public sealed record EvidenceProvenance(string LedgerEntryId, string EvidenceBundleId); +public sealed record PolicyRationale(string Id, string Summary); + public sealed record VulnListResponse(IReadOnlyList Items, string? NextPageToken); diff --git a/src/VulnExplorer/StellaOps.VulnExplorer.Api/Program.cs b/src/VulnExplorer/StellaOps.VulnExplorer.Api/Program.cs index 35b4f296b..ef88d42c4 100644 --- a/src/VulnExplorer/StellaOps.VulnExplorer.Api/Program.cs +++ b/src/VulnExplorer/StellaOps.VulnExplorer.Api/Program.cs @@ -1,28 +1,36 @@ +using System.Collections.Generic; +using Swashbuckle.AspNetCore.SwaggerGen; using System.Globalization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.OpenApi; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; using StellaOps.VulnExplorer.Api.Data; using StellaOps.VulnExplorer.Api.Models; var builder = WebApplication.CreateBuilder(args); builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddOpenApi(); +builder.Services.AddSwaggerGen(options => +{ + options.SwaggerDoc("v1", new OpenApiInfo + { + Title = "StellaOps Vuln Explorer API", + Version = "v1", + Description = "Deterministic vulnerability listing/detail endpoints" + }); +}); var app = builder.Build(); -if (app.Environment.IsDevelopment()) -{ - app.MapOpenApi(); -} +app.UseSwagger(); +app.UseSwaggerUI(); app.UseHttpsRedirection(); -app.MapGet("/v1/vulns", ( - HttpRequest request, - [AsParameters] VulnFilter filter) => +app.MapGet("/v1/vulns", ([AsParameters] VulnFilter filter) => { - var tenant = request.Headers["x-stella-tenant"].ToString(); - if (string.IsNullOrWhiteSpace(tenant)) + if (string.IsNullOrWhiteSpace(filter.Tenant)) { return Results.BadRequest(new { error = "x-stella-tenant required" }); } @@ -40,9 +48,8 @@ app.MapGet("/v1/vulns", ( }) .WithOpenApi(); -app.MapGet("/v1/vulns/{id}", (HttpRequest request, string id) => +app.MapGet("/v1/vulns/{id}", ([FromHeader(Name = "x-stella-tenant")] string? tenant, string id) => { - var tenant = request.Headers["x-stella-tenant"].ToString(); if (string.IsNullOrWhiteSpace(tenant)) { return Results.BadRequest(new { error = "x-stella-tenant required" }); @@ -63,19 +70,19 @@ static IReadOnlyList ApplyFilter(IReadOnlyList source, { IEnumerable query = source; - if (filter.Cve?.Count > 0) + if (filter.Cve is { Length: > 0 }) { var set = filter.Cve.ToHashSet(StringComparer.OrdinalIgnoreCase); query = query.Where(v => v.CveIds.Any(set.Contains)); } - if (filter.Purl?.Count > 0) + if (filter.Purl is { Length: > 0 }) { var set = filter.Purl.ToHashSet(StringComparer.OrdinalIgnoreCase); query = query.Where(v => v.Purls.Any(set.Contains)); } - if (filter.Severity?.Count > 0) + if (filter.Severity is { Length: > 0 }) { var set = filter.Severity.ToHashSet(StringComparer.OrdinalIgnoreCase); query = query.Where(v => set.Contains(v.Severity)); @@ -100,13 +107,13 @@ static IReadOnlyList ApplyFilter(IReadOnlyList source, } public record VulnFilter( - [FromHeader(Name = "x-stella-tenant")] string Tenant, + [FromHeader(Name = "x-stella-tenant")] string? Tenant, [FromQuery(Name = "policyVersion")] string? PolicyVersion, [FromQuery(Name = "pageSize")] int? PageSize, [FromQuery(Name = "pageToken")] string? PageToken, - [FromQuery(Name = "cve")] IReadOnlyList? Cve, - [FromQuery(Name = "purl")] IReadOnlyList? Purl, - [FromQuery(Name = "severity")] IReadOnlyList? Severity, + [FromQuery(Name = "cve")] string[]? Cve, + [FromQuery(Name = "purl")] string[]? Purl, + [FromQuery(Name = "severity")] string[]? Severity, [FromQuery(Name = "exploitability")] string? Exploitability, [FromQuery(Name = "fixAvailable")] bool? FixAvailable); diff --git a/src/VulnExplorer/StellaOps.VulnExplorer.Api/StellaOps.VulnExplorer.Api.csproj b/src/VulnExplorer/StellaOps.VulnExplorer.Api/StellaOps.VulnExplorer.Api.csproj index 19c979402..d11e870bb 100644 --- a/src/VulnExplorer/StellaOps.VulnExplorer.Api/StellaOps.VulnExplorer.Api.csproj +++ b/src/VulnExplorer/StellaOps.VulnExplorer.Api/StellaOps.VulnExplorer.Api.csproj @@ -10,5 +10,6 @@ + diff --git a/src/VulnExplorer/StellaOps.VulnExplorer.Api/TASKS.md b/src/VulnExplorer/StellaOps.VulnExplorer.Api/TASKS.md new file mode 100644 index 000000000..061e334ae --- /dev/null +++ b/src/VulnExplorer/StellaOps.VulnExplorer.Api/TASKS.md @@ -0,0 +1,7 @@ +# Vuln Explorer API Tasks (Sprint 0129-0001-0001) + +| Task ID | Status | Notes | +| --- | --- | --- | +| VULN-API-29-001 | DONE (2025-11-25) | OpenAPI v1 draft published at `docs/modules/vuln-explorer/openapi/vuln-explorer.v1.yaml` with tenant header, filters, deterministic paging. | +| VULN-API-29-002 | DONE (2025-11-25) | Implemented `/v1/vulns` list + `/v1/vulns/{id}` detail with deterministic paging/filtering, sample data, Swagger UI; tests green (`tests/TestResults/vuln-explorer/api.trx`). | +| VULN-API-29-003 | DONE (2025-11-25) | Detail endpoint now returns rationale, paths, evidence references; covered by Vuln Explorer API integration tests. | diff --git a/tests/StellaOps.VulnExplorer.Api.Tests/StellaOps.VulnExplorer.Api.Tests.csproj b/tests/StellaOps.VulnExplorer.Api.Tests/StellaOps.VulnExplorer.Api.Tests.csproj index 527fb35c7..c8bbbf6b9 100644 --- a/tests/StellaOps.VulnExplorer.Api.Tests/StellaOps.VulnExplorer.Api.Tests.csproj +++ b/tests/StellaOps.VulnExplorer.Api.Tests/StellaOps.VulnExplorer.Api.Tests.csproj @@ -9,7 +9,8 @@ false - + + diff --git a/tests/StellaOps.VulnExplorer.Api.Tests/VulnApiTests.cs b/tests/StellaOps.VulnExplorer.Api.Tests/VulnApiTests.cs index eb20c0c66..b64278db9 100644 --- a/tests/StellaOps.VulnExplorer.Api.Tests/VulnApiTests.cs +++ b/tests/StellaOps.VulnExplorer.Api.Tests/VulnApiTests.cs @@ -2,6 +2,7 @@ using System.Net; using System.Net.Http.Json; using Microsoft.AspNetCore.Mvc.Testing; using StellaOps.VulnExplorer.Api.Models; +using Xunit; namespace StellaOps.VulnExplorer.Api.Tests; @@ -51,4 +52,20 @@ public class VulnApiTests : IClassFixture> var response = await client.GetAsync("/v1/vulns/missing"); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } + + [Fact] + public async Task Detail_ReturnsRationaleAndPaths() + { + var client = factory.CreateClient(); + client.DefaultRequestHeaders.Add("x-stella-tenant", "tenant-a"); + + var response = await client.GetAsync("/v1/vulns/vuln-0001"); + response.EnsureSuccessStatusCode(); + + var detail = await response.Content.ReadFromJsonAsync(); + Assert.NotNull(detail); + Assert.Equal("rat-0001", detail!.Rationale.Id); + Assert.Contains("/src/app/Program.cs", detail.Paths); + Assert.NotEmpty(detail.Evidence); + } } diff --git a/tools/run-airgap-bundle-tests.sh b/tools/run-airgap-bundle-tests.sh new file mode 100644 index 000000000..5cec16bca --- /dev/null +++ b/tools/run-airgap-bundle-tests.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Runs only the Airgap bundle determinism tests for Concelier WebService. +# Intended for CI runners with warmed NuGet cache; keeps outputs deterministic. + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +RESULTS_DIR="${RESULTS_DIR:-${ROOT_DIR}/TestResults}" + +mkdir -p "${RESULTS_DIR}" + +pushd "${ROOT_DIR}" >/dev/null + +dotnet test \ + src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj \ + -c Release \ + --filter AirgapBundleBuilderTests \ + --logger "trx;LogFileName=airgap-bundle.trx" \ + -- ResultsDirectory="${RESULTS_DIR}" + +popd >/dev/null + +echo "Airgap bundle tests complete. TRX: ${RESULTS_DIR}/airgap-bundle.trx"