# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview **Stella Ops Suite** is a self-hostable, sovereign release control plane for non-Kubernetes container estates, released under AGPL-3.0-or-later. It orchestrates environment promotions (Dev → Stage → Prod), gates releases using reachability-aware security and policy, and produces verifiable evidence for every release decision. The platform combines: - **Release orchestration** — UI-driven promotion, approvals, policy gates, rollbacks; hook-able with scripts - **Security decisioning as a gate** — Scan on build, evaluate on release, re-evaluate on CVE updates - **OCI-digest-first releases** — Immutable digest-based release identity with "what is deployed where" tracking - **Toolchain-agnostic integrations** — Plug into any SCM, CI, registry, and secrets system - **Auditability + standards** — Evidence packets, SBOM/VEX/attestation support, deterministic replay Existing capabilities (operational): Reproducible vulnerability scanning with VEX-first decisioning, SBOM generation (SPDX 2.2/2.3 and CycloneDX 1.7; SPDX 3.0.1 planned), in-toto/DSSE attestations, and optional Sigstore Rekor transparency. The platform is designed for offline/air-gapped operation with regional crypto support (eIDAS/FIPS/GOST/SM). Planned capabilities (release orchestration): Environment management, release bundles, promotion workflows, deployment execution (Docker/Compose/ECS/Nomad agents), progressive delivery (A/B, canary), and a three-surface plugin system. See `docs/modules/release-orchestrator/README.md` for the full specification. ## Build Commands ```bash # Build the entire solution dotnet build src/StellaOps.sln # Build a specific module (example: Concelier web service) dotnet build src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj # Run the Concelier web service dotnet run --project src/Concelier/StellaOps.Concelier.WebService # Build CLI for current platform dotnet publish src/Cli/StellaOps.Cli/StellaOps.Cli.csproj --configuration Release # Build CLI for specific runtime (linux-x64, linux-arm64, osx-x64, osx-arm64, win-x64) dotnet publish src/Cli/StellaOps.Cli/StellaOps.Cli.csproj --configuration Release --runtime linux-x64 ``` ## Test Commands ```bash # Run all tests dotnet test src/StellaOps.sln # Run tests for a specific project dotnet test src/Scanner/__Tests/StellaOps.Scanner.WebService.Tests/StellaOps.Scanner.WebService.Tests.csproj # Run a single test by filter dotnet test --filter "FullyQualifiedName~TestMethodName" # Run tests with verbosity dotnet test src/StellaOps.sln --verbosity normal ``` **Note:** Integration tests use Testcontainers for PostgreSQL. Ensure Docker is running before executing tests. ## Linting and Validation ```bash # Lint OpenAPI specs npm run api:lint # Validate attestation schemas npm run docs:attestor:validate # Validate Helm chart helm lint devops/helm/stellaops # Validate Docker Compose profiles ./devops/scripts/validate-compose.sh # Run local CI tests ./devops/scripts/test-local.sh ``` ## Architecture ### Technology Stack - **Runtime:** .NET 10 (`net10.0`) with latest C# preview features - **Frontend:** Angular v17 (in `src/Web/StellaOps.Web`) - **Database:** PostgreSQL (≥16) with per-module schema isolation; see `docs/db/` for specification - **Testing:** xUnit with Testcontainers (PostgreSQL), Moq, Microsoft.AspNetCore.Mvc.Testing - **Observability:** Structured logging, OpenTelemetry traces - **NuGet:** Uses standard NuGet feeds configured in `nuget.config` (dotnet-public, nuget-mirror, nuget.org) ### Module Structure The codebase follows a monorepo pattern with modules under `src/`: | Module | Path | Purpose | |--------|------|---------| | **Core Platform** | | | | Authority | `src/Authority/` | Authentication, authorization, OAuth/OIDC, DPoP | | Gateway | `src/Gateway/` | API gateway with routing and transport abstraction | | Router | `src/Router/` | Transport-agnostic messaging (TCP/TLS/UDP/RabbitMQ/Valkey) | | Platform | `src/Platform/` | Console backend aggregation service (health, quotas, search) | | Registry | `src/Registry/` | Token service for container registry authentication | | **Data Ingestion** | | | | Concelier | `src/Concelier/` | Vulnerability advisory ingestion and merge engine | | Excititor | `src/Excititor/` | VEX document ingestion and export | | VexLens | `src/VexLens/` | VEX consensus computation across issuers | | VexHub | `src/VexHub/` | VEX distribution and exchange hub | | IssuerDirectory | `src/IssuerDirectory/` | Issuer trust registry (CSAF publishers) | | Feedser | `src/Feedser/` | Evidence collection library for backport detection | | Mirror | `src/Concelier/__Libraries/` | Vulnerability feed mirror connector (Concelier plugin) | | **Scanning & Analysis** | | | | Scanner | `src/Scanner/` | Container scanning with SBOM generation (11 language analyzers) | | BinaryIndex | `src/BinaryIndex/` | Binary identity extraction and fingerprinting | | AdvisoryAI | `src/AdvisoryAI/` | AI-assisted advisory analysis | | ReachGraph | `src/ReachGraph/` | Reachability graph service | | Symbols | `src/Symbols/` | Symbol resolution and debug information | | Cartographer | `src/Cartographer/` | Dependency graph mapping and visualization | | **Artifacts & Evidence** | | | | Attestor | `src/Attestor/` | in-toto/DSSE attestation generation | | Signer | `src/Signer/` | Cryptographic signing operations | | SbomService | `src/SbomService/` | SBOM storage, versioning, and lineage ledger | | EvidenceLocker | `src/EvidenceLocker/` | Sealed evidence storage and export | | ExportCenter | `src/ExportCenter/` | Batch export and report generation | | Provenance | `src/Provenance/` | SLSA/DSSE attestation tooling | | **Policy & Risk** | | | | Policy | `src/Policy/` | Policy engine with K4 lattice logic | | RiskEngine | `src/RiskEngine/` | Risk scoring runtime with pluggable providers | | VulnExplorer | `src/VulnExplorer/` | Vulnerability exploration and triage UI backend | | Unknowns | `src/Unknowns/` | Unknown component and symbol tracking | | Findings | `src/Findings/` | Findings ledger service for vulnerability tracking | | **Operations** | | | | Scheduler | `src/Scheduler/` | Job scheduling and queue management | | Orchestrator | `src/Orchestrator/` | Workflow orchestration and task coordination | | TaskRunner | `src/TaskRunner/` | Task pack execution engine | | Notify | `src/Notify/` | Notification toolkit (Email, Slack, Teams, Webhooks) | | Notifier | `src/Notifier/` | Notifications Studio host | | PacksRegistry | `src/PacksRegistry/` | Task packs registry and distribution | | TimelineIndexer | `src/TimelineIndexer/` | Timeline event indexing | | Replay | `src/Replay/` | Deterministic replay engine | | **Integration** | | | | CLI | `src/Cli/` | Command-line interface (Native AOT) | | Zastava | `src/Zastava/` | Container registry webhook observer | | Web | `src/Web/` | Angular 17 frontend SPA | | Integrations | `src/Integrations/` | External system integrations web service | | **Infrastructure** | | | | Cryptography | `src/Cryptography/` | Crypto plugins (FIPS, eIDAS, GOST, SM, PQ) | | Telemetry | `src/Telemetry/` | OpenTelemetry traces, metrics, logging | | Graph | `src/Graph/` | Call graph and reachability data structures | | Signals | `src/Signals/` | Runtime signal collection and correlation | | AirGap | `src/AirGap/` | Air-gapped deployment support | | AOC | `src/Aoc/` | Append-Only Contract enforcement (Roslyn analyzers) | | SmRemote | `src/SmRemote/` | SM2/SM3/SM4 cryptographic remote service | | **Development Tools** | | | | Tools | `src/Tools/` | Development utilities (fixture updater, smoke tests, validators) | | Bench | `src/Bench/` | Performance benchmark infrastructure | > **Note:** See `docs/modules//architecture.md` for detailed module dossiers. Some entries in `docs/modules/` are cross-cutting concepts (snapshot, triage) or shared libraries (provcache) rather than standalone modules. ### Code Organization Patterns - **Libraries:** `src//__Libraries/StellaOps..*` - **Tests:** `src//__Tests/StellaOps..*.Tests/` - **Plugins:** Follow naming `StellaOps..Connector.*` or `StellaOps..Plugin.*` - **Shared test infrastructure:** `StellaOps.Concelier.Testing` and `StellaOps.Infrastructure.Postgres.Testing` provide PostgreSQL fixtures ### Naming Conventions - All modules are .NET 10 projects, except the UI (Angular) - Module projects: `StellaOps.` - Libraries/plugins common to multiple modules: `StellaOps.` - Each project lives in its own folder ### Key Glossary - **OVAL** — Vendor/distro security definition format; authoritative for OS packages - **NEVRA / EVR** — RPM and Debian version semantics for OS packages - **PURL / SemVer** — Coordinates and version semantics for OSS ecosystems - **KEV** — Known Exploited Vulnerabilities (flag only) ## Coding Rules ### Core Principles 1. **Determinism:** Outputs must be reproducible - stable ordering, UTC ISO-8601 timestamps, immutable NDJSON where applicable 2. **Offline-first:** Remote host allowlist, strict schema validation, avoid hard-coded external dependencies unless explicitly allowed 3. **Plugin architecture:** Concelier connectors, Authority plugins, Scanner analyzers are all plugin-based 4. **VEX-first decisioning:** Exploitability modeled in OpenVEX with lattice logic for stable outcomes ### Implementation Guidelines - Follow .NET 10 and Angular v17 best practices - Apply SOLID principles (SRP, OCP, LSP, ISP, DIP) when designing services, libraries, and tests - Keep in mind the nuget versions are controlled centrally by src/Directory* files, not via csproj - Maximise reuse and composability - Never regress determinism, ordering, or precedence - Every change must be accompanied by or covered by tests - Gated LLM usage (only where explicitly configured) ### Test Layout - **Module tests:** `src//__Tests/StellaOps...Tests/` - **Global tests:** `src/__Tests/{Category}/` (Integration, Acceptance, Load, Security, Chaos, E2E, etc.) - **Shared testing libraries:** `src/__Tests/__Libraries/StellaOps.*.Testing/` - **Benchmarks & golden corpus:** `src/__Tests/__Benchmarks/` - **Ground truth datasets:** `src/__Tests/__Datasets/` - Tests use xUnit, Testcontainers for PostgreSQL integration tests - See `src/__Tests/AGENTS.md` for detailed test infrastructure guidance ## Code Quality & Determinism Rules These rules were distilled from a comprehensive audit of 324+ projects. They address the most common recurring issues and must be followed by all implementers. ### 8.1) Compiler & Warning Discipline | Rule | Guidance | |------|----------| | **Enable TreatWarningsAsErrors** | All projects must set `true` in the `.csproj` or via `Directory.Build.props`. Relaxed warnings mask regressions and code quality drift. | ```xml true ``` ### 8.2) Deterministic Time & ID Generation | Rule | Guidance | |------|----------| | **Inject TimeProvider / ID generators** | Never use `DateTime.UtcNow`, `DateTimeOffset.UtcNow`, `Guid.NewGuid()`, or `Random.Shared` directly in production code. Inject `TimeProvider` (or `ITimeProvider`) and `IGuidGenerator` abstractions. | ```csharp // BAD - nondeterministic, hard to test public class BadService { public Record CreateRecord() => new Record { Id = Guid.NewGuid(), CreatedAt = DateTimeOffset.UtcNow }; } // GOOD - injectable, testable, deterministic public class GoodService(TimeProvider timeProvider, IGuidGenerator guidGenerator) { public Record CreateRecord() => new Record { Id = guidGenerator.NewGuid(), CreatedAt = timeProvider.GetUtcNow() }; } ``` ### 8.2.1) Resolver Version Tracking | Rule | Guidance | |------|----------| | **Include resolver/engine version in snapshots** | For strict reproducibility verification, include the resolver or engine version digest in `KnowledgeSnapshot` and similar input manifests. This ensures that identical inputs processed by different engine versions can be detected and flagged. | ```csharp // BAD - snapshot missing engine version public sealed record KnowledgeSnapshot { public required ImmutableArray Sboms { get; init; } public required ImmutableArray VexDocuments { get; init; } // Missing: engine version that produced the verdict } // GOOD - includes engine version for reproducibility verification public sealed record KnowledgeSnapshot { public required ImmutableArray Sboms { get; init; } public required ImmutableArray VexDocuments { get; init; } public required EngineVersionRef EngineVersion { get; init; } } public sealed record EngineVersionRef( string EngineName, // e.g., "VexConsensusEngine" string Version, // e.g., "2.1.0" string SourceDigest); // SHA-256 of engine source or build artifact ``` ### 8.3) ASCII-Only Output | Rule | Guidance | |------|----------| | **No mojibake or non-ASCII glyphs** | Use ASCII-only characters in comments, output strings, and log messages. No `ƒ?`, `バ`, `→`, `✓`, `✗`, or box-drawing characters. When Unicode is truly required, use explicit escapes (`\uXXXX`) and document the rationale. | ```csharp // BAD - non-ASCII glyphs Console.WriteLine("✓ Success → proceeding"); // or mojibake comments like: // ƒ+ validation passed // GOOD - ASCII only Console.WriteLine("[OK] Success - proceeding"); // Comment: validation passed ``` ### 8.4) Test Project Requirements | Rule | Guidance | |------|----------| | **Every library needs tests** | All production libraries/services must have a corresponding `*.Tests` project covering: (a) happy paths, (b) error/edge cases, (c) determinism, and (d) serialization round-trips. | ``` src/ Scanner/ __Libraries/ StellaOps.Scanner.Core/ __Tests/ StellaOps.Scanner.Core.Tests/ <-- Required ``` ### 8.5) Culture-Invariant Parsing | Rule | Guidance | |------|----------| | **Use InvariantCulture** | Always use `CultureInfo.InvariantCulture` for parsing and formatting dates, numbers, percentages, and any string that will be persisted, hashed, or compared. Current culture causes locale-dependent, nondeterministic behavior. | ```csharp // BAD - culture-sensitive var value = double.Parse(input); var formatted = percentage.ToString("P2"); // GOOD - invariant culture var value = double.Parse(input, CultureInfo.InvariantCulture); var formatted = percentage.ToString("P2", CultureInfo.InvariantCulture); ``` ### 8.6) DSSE PAE Consistency | Rule | Guidance | |------|----------| | **Single DSSE PAE implementation** | Use one spec-compliant DSSE PAE helper (`StellaOps.Attestation.DsseHelper` or equivalent) across the codebase. DSSE v1 requires ASCII decimal lengths and space separators. Never reimplement PAE encoding. | ```csharp // BAD - custom PAE implementation var pae = $"DSSEv1 {payloadType.Length} {payloadType} {payload.Length} "; // GOOD - use shared helper var pae = DsseHelper.ComputePreAuthenticationEncoding(payloadType, payload); ``` ### 8.7) RFC 8785 JSON Canonicalization | Rule | Guidance | |------|----------| | **Use shared RFC 8785 canonicalizer** | For digest/signature inputs, use a shared RFC 8785-compliant JSON canonicalizer with: sorted keys, minimal escaping per spec, no exponent notation for numbers, no trailing/leading zeros. Do not use `UnsafeRelaxedJsonEscaping` or `CamelCase` naming for canonical outputs. | ```csharp // BAD - non-canonical JSON var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); // GOOD - use shared canonicalizer var canonicalJson = CanonicalJsonSerializer.Serialize(obj); var digest = ComputeDigest(canonicalJson); ``` ### 8.8) CancellationToken Propagation | Rule | Guidance | |------|----------| | **Propagate CancellationToken** | Always propagate `CancellationToken` through async call chains. Never use `CancellationToken.None` in production code except at entry points where no token is available. | ```csharp // BAD - ignores cancellation public async Task ProcessAsync(CancellationToken ct) { await _repository.SaveAsync(data, CancellationToken.None); // Wrong! await Task.Delay(1000); // Missing ct } // GOOD - propagates cancellation public async Task ProcessAsync(CancellationToken ct) { await _repository.SaveAsync(data, ct); await Task.Delay(1000, ct); } ``` ### 8.9) HttpClient via Factory | Rule | Guidance | |------|----------| | **Use IHttpClientFactory** | Never `new HttpClient()` directly. Use `IHttpClientFactory` with configured timeouts and retry policies via Polly or `Microsoft.Extensions.Http.Resilience`. Direct HttpClient creation risks socket exhaustion. | ```csharp // BAD - direct instantiation public class BadService { public async Task FetchAsync() { using var client = new HttpClient(); // Socket exhaustion risk await client.GetAsync(url); } } // GOOD - factory with resilience public class GoodService(IHttpClientFactory httpClientFactory) { public async Task FetchAsync() { var client = httpClientFactory.CreateClient("MyApi"); await client.GetAsync(url); } } // Registration with timeout/retry services.AddHttpClient("MyApi") .ConfigureHttpClient(c => c.Timeout = TimeSpan.FromSeconds(30)) .AddStandardResilienceHandler(); ``` ### 8.10) Path/Root Resolution | Rule | Guidance | |------|----------| | **Explicit CLI options for paths** | Do not derive repository root from `AppContext.BaseDirectory` with parent directory walks. Use explicit CLI options (`--repo-root`) or environment variables. Provide sensible defaults with clear error messages. | ```csharp // BAD - fragile parent walks var repoRoot = Path.GetFullPath(Path.Combine( AppContext.BaseDirectory, "..", "..", "..", "..")); // GOOD - explicit option with fallback [Option("--repo-root", Description = "Repository root path")] public string? RepoRoot { get; set; } public string GetRepoRoot() => RepoRoot ?? Environment.GetEnvironmentVariable("STELLAOPS_REPO_ROOT") ?? throw new InvalidOperationException("Repository root not specified. Use --repo-root or set STELLAOPS_REPO_ROOT."); ``` ### 8.11) Test Categorization | Rule | Guidance | |------|----------| | **Correct test categories** | Tag tests correctly: `[Trait("Category", "Unit")]` for pure unit tests, `[Trait("Category", "Integration")]` for tests requiring databases, containers, or network. Don't mix DB/network tests into unit suites. | ```csharp // BAD - integration test marked as unit public class UserRepositoryTests // Uses Testcontainers/Postgres { [Fact] // Missing category, runs with unit tests public async Task Save_PersistsUser() { ... } } // GOOD - correctly categorized [Trait("Category", "Integration")] public class UserRepositoryTests { [Fact] public async Task Save_PersistsUser() { ... } } [Trait("Category", "Unit")] public class UserValidatorTests { [Fact] public void Validate_EmptyEmail_ReturnsFalse() { ... } } ``` ### 8.12) No Silent Stubs | Rule | Guidance | |------|----------| | **Unimplemented code must throw** | Placeholder code must throw `NotImplementedException` or return an explicit error/unsupported status. Never return success (`null`, empty results, or success codes) from unimplemented paths. | ```csharp // BAD - silent stub masks missing implementation public async Task ProcessAsync() { // TODO: implement later return Result.Success(); // Ships broken feature! } // GOOD - explicit failure public async Task ProcessAsync() { throw new NotImplementedException("ProcessAsync not yet implemented. See SPRINT_XYZ."); } ``` ### 8.13) Immutable Collection Returns | Rule | Guidance | |------|----------| | **Return immutable collections** | Public APIs must return `IReadOnlyList`, `ImmutableArray`, or defensive copies. Never expose mutable backing stores that callers can mutate. | ```csharp // BAD - exposes mutable backing store public class BadRegistry { private readonly List _scopes = new(); public List Scopes => _scopes; // Callers can mutate! } // GOOD - immutable return public class GoodRegistry { private readonly List _scopes = new(); public IReadOnlyList Scopes => _scopes.AsReadOnly(); // or: public ImmutableArray Scopes => _scopes.ToImmutableArray(); } ``` ### 8.14) Options Validation at Startup | Rule | Guidance | |------|----------| | **ValidateOnStart for options** | Use `ValidateDataAnnotations()` and `ValidateOnStart()` for options. Implement `IValidateOptions` for complex validation. All required config must be validated at startup, not at first use. | ```csharp // BAD - no validation until runtime failure services.Configure(config.GetSection("My")); // GOOD - validated at startup services.AddOptions() .Bind(config.GetSection("My")) .ValidateDataAnnotations() .ValidateOnStart(); // With complex validation public class MyOptionsValidator : IValidateOptions { public ValidateOptionsResult Validate(string? name, MyOptions options) { if (options.Timeout <= TimeSpan.Zero) return ValidateOptionsResult.Fail("Timeout must be positive"); return ValidateOptionsResult.Success; } } ``` ### 8.15) No Backup Files in Source | Rule | Guidance | |------|----------| | **Exclude backup/temp artifacts** | Add backup patterns (`*.Backup.tmp`, `*.bak`, `*.orig`) to `.gitignore`. Regularly audit for and remove stray artifacts. Consolidate duplicate tools/harnesses. | ```gitignore # .gitignore additions *.Backup.tmp *.bak *.orig *~ ``` ### 8.16) Test Production Code, Not Reimplementations | Rule | Guidance | |------|----------| | **Helpers call production code** | Test helpers must call production code, not reimplement algorithms (Merkle trees, DSSE PAE, parsers, canonicalizers). Only mock I/O and network boundaries. Reimplementations cause test/production drift. | ```csharp // BAD - test reimplements production logic [Fact] public void Merkle_ComputesCorrectRoot() { // Custom Merkle implementation in test var root = TestMerkleHelper.ComputeRoot(leaves); // Drift risk! Assert.Equal(expected, root); } // GOOD - test exercises production code [Fact] public void Merkle_ComputesCorrectRoot() { // Uses production MerkleTreeBuilder var root = MerkleTreeBuilder.ComputeRoot(leaves); Assert.Equal(expected, root); } ``` ### 8.17) Bounded Caches with Eviction | Rule | Guidance | |------|----------| | **No unbounded Dictionary caches** | Do not use `ConcurrentDictionary` or `Dictionary` for caching without eviction policies. Use bounded caches with TTL/LRU eviction (`MemoryCache` with size limits, or external cache like Valkey). Document expected cardinality and eviction behavior. | ```csharp // BAD - unbounded growth private readonly ConcurrentDictionary _cache = new(); public void Add(string key, CacheEntry entry) { _cache[key] = entry; // Never evicts, memory grows forever } // GOOD - bounded with eviction private readonly MemoryCache _cache = new(new MemoryCacheOptions { SizeLimit = 10_000 }); public void Add(string key, CacheEntry entry) { _cache.Set(key, entry, new MemoryCacheEntryOptions { Size = 1, SlidingExpiration = TimeSpan.FromMinutes(30) }); } ``` ### 8.18) DateTimeOffset for PostgreSQL timestamptz | Rule | Guidance | |------|----------| | **Use GetFieldValue<DateTimeOffset>** | PostgreSQL `timestamptz` columns must be read via `reader.GetFieldValue()`, not `reader.GetDateTime()`. `GetDateTime()` loses offset information and causes UTC/local confusion. Store and retrieve all timestamps as UTC `DateTimeOffset`. | ```csharp // BAD - loses offset information var createdAt = reader.GetDateTime(reader.GetOrdinal("created_at")); // GOOD - preserves offset var createdAt = reader.GetFieldValue(reader.GetOrdinal("created_at")); ``` ### 8.19) Hybrid Logical Clock (HLC) Usage | Rule | Guidance | |------|----------| | **Use IHybridLogicalClock for ordering** | For distributed ordering and audit-safe sequencing, use `IHybridLogicalClock` from `StellaOps.HybridLogicalClock`. Never rely on wall-clock time alone for ordering in distributed scenarios. | ```csharp // BAD - wall-clock ordering in distributed system public async Task EnqueueAsync(Job job) { job.EnqueuedAt = DateTimeOffset.UtcNow; // Clock skew risk! await _store.SaveAsync(job); } // GOOD - HLC ordering public async Task EnqueueAsync(Job job, CancellationToken ct) { job.THlc = _hlc.Tick(); // Monotonic, skew-tolerant job.EnqueuedAtWall = _timeProvider.GetUtcNow(); // Informational only await _store.SaveAsync(job, ct); } ``` | Rule | Guidance | |------|----------| | **Deterministic event IDs** | Generate event IDs deterministically from content, not randomly. Use `SHA-256(correlationId \|\| tHlc \|\| service \|\| kind)` for timeline events. This ensures replay produces identical IDs. | ```csharp // BAD - random ID breaks replay determinism var eventId = Guid.NewGuid().ToString(); // GOOD - deterministic ID from content var eventId = EventIdGenerator.Generate(correlationId, tHlc, service, kind); // Returns: SHA-256(inputs)[0:32] as hex ``` | Rule | Guidance | |------|----------| | **HLC state persistence** | Persist HLC state on graceful shutdown via `IHlcStateStore`. On startup, call `InitializeFromStateAsync()` to restore monotonicity. This prevents HLC regression after restarts. | ```csharp // Service startup public async Task StartAsync(CancellationToken ct) { await _hlc.InitializeFromStateAsync(ct); // HLC will now be >= last persisted value } // Service shutdown public async Task StopAsync(CancellationToken ct) { await _hlc.PersistStateAsync(ct); } ``` | Rule | Guidance | |------|----------| | **HLC in event envelopes** | Timeline events must include both `tHlc` (ordering) and `tsWall` (debugging). Use `HlcTimestamp.ToSortableString()` for string representation. Never parse HLC from user input without validation. | | Rule | Guidance | |------|----------| | **Clock skew handling** | Configure reasonable `MaxClockSkew` tolerance (default: 5 seconds). Events with excessive skew throw `HlcClockSkewException`. Monitor `hlc_clock_skew_rejections_total` metric. | **Reference:** See `docs/modules/eventing/event-envelope-schema.md` for the canonical event envelope specification. ### Documentation Updates When scope, contracts, or workflows change, update the relevant docs under: - `docs/modules/**` - Module architecture dossiers - `docs/api/` - API documentation - `docs/modules/risk-engine/` - Risk documentation - `docs/airgap/` - Air-gap operation docs ## Role-Based Behavior When working in this repository, behavior changes based on the role specified: ### As Implementer (Default for coding tasks) - Work only inside the module's directory defined by the sprint's "Working directory" - Cross-module edits require explicit notes in commit/PR descriptions - Do **not** ask clarification questions - if ambiguity exists: - Mark the task as `BLOCKED` in the sprint `Delivery Tracker` - Add a note in `Decisions & Risks` describing the issue - Skip to the next unblocked task - Maintain status tracking: `TODO → DOING → DONE/BLOCKED` in sprint files - Read the module's `AGENTS.md` before coding in that module ### As Project Manager Create implementation sprint files under `docs/implplan/` using the **mandatory** sprint filename format: `SPRINT____.md` - ``: implementation epoch (e.g., `20251219`). Determine by scanning existing `docs/implplan/SPRINT_*.md` and using the highest epoch; if none exist, use today's epoch. - ``: `001`, `002`, etc. — grouping when more than one sprint is needed for a feature. - ``: `FE` (Frontend), `BE` (Backend), `AG` (Agent), `LB` (library), `BE` (Backend), `AG` (Agent), `LB` (library), 'SCANNER' (scanner), 'AUTH' (Authority), 'CONCEL' (Concelier), 'CONCEL-ASTRA' - (Concelier Astra source connecto) and etc. - ``: short topic description. - **If any existing sprint file name or internal format deviates from the standard, rename/normalize it** and record the change in its **Execution Log**. - Normalize sprint files to standard template while preserving content - Ensure module `AGENTS.md` files exist and are up to date - When sprint is fully completed move it to `docs-archived/implplan/` ### As Product Manager - Review advisories in `docs/product/advisories/` - Check for overlaps with `docs-archived/product/advisories/` - Validate against module docs and existing implementations - Hand over to project manager role for sprint/task definition ## Task Workflow ### Status Discipline Always update task status in `docs/implplan/SPRINT_*.md`: - `TODO` - Not started - `DOING` - In progress - `DONE` - Completed - `BLOCKED` - Waiting on decision/clarification ### Prerequisites Before coding, confirm required docs are read: - `docs/README.md` - `docs/ARCHITECTURE_REFERENCE.md` - `docs/modules/platform/architecture-overview.md` - Relevant module dossier (e.g., `docs/modules//architecture.md`) - Module-specific `AGENTS.md` file ### Git Rules - Never use `git reset` unless explicitly told to do so - Never skip hooks (--no-verify, --no-gpg-sign) unless explicitly requested ## Configuration - **Sample configs:** `etc/concelier.yaml.sample`, `etc/authority.yaml.sample` - **Plugin manifests:** `etc/authority.plugins/*.yaml` - **NuGet sources:** Package cache in `.nuget/packages/`, public sources configured in `nuget.config` ## Documentation - **Architecture overview:** `docs/ARCHITECTURE_OVERVIEW.md` - **Architecture reference:** `docs/ARCHITECTURE_REFERENCE.md` - **Module dossiers:** `docs/modules//architecture.md` - **Database specification:** `docs/db/SPECIFICATION.md` - **PostgreSQL operations:** `docs/operations/postgresql-guide.md` - **API/CLI reference:** `docs/API_CLI_REFERENCE.md` - **Offline operation:** `docs/OFFLINE_KIT.md` - **Quickstart:** `docs/CONCELIER_CLI_QUICKSTART.md` - **Sprint planning:** `docs/implplan/SPRINT_*.md` ## CI/CD ### Folder Structure The CI/CD infrastructure uses a two-tier organization: | Folder | Purpose | |--------|---------| | `.gitea/workflows/` | Gitea Actions workflow YAML files (87+) | | `.gitea/scripts/` | CI/CD scripts called by workflows | | `devops/` | Deployment, tooling, and operational configs | ### CI/CD Scripts (`.gitea/scripts/`) ``` .gitea/scripts/ ├── build/ # Build orchestration (build-cli.sh, build-multiarch.sh) ├── test/ # Test execution (test-lane.sh, determinism-run.sh) ├── validate/ # Validation (validate-sbom.sh, validate-helm.sh) ├── sign/ # Signing (sign-signals.sh, publish-attestation.sh) ├── release/ # Release automation (build_release.py, verify_release.py) ├── metrics/ # Performance metrics (compute-reachability-metrics.sh) ├── evidence/ # Evidence bundles (upload-all-evidence.sh) └── util/ # Utilities (cleanup-runner-space.sh) ``` ### DevOps Folder (`devops/`) ``` devops/ ├── compose/ # Docker Compose profiles (dev, stage, prod, airgap) ├── helm/ # Helm charts (stellaops) ├── docker/ # Dockerfiles (platform, crypto-profile, ci) ├── telemetry/ # OpenTelemetry, Prometheus, Grafana configs ├── services/ # Service-specific configs (authority, crypto, signals) ├── offline/ # Air-gap and offline deployment ├── observability/ # Alerts, SLOs, incident management ├── database/ # PostgreSQL and MongoDB configs ├── ansible/ # Ansible playbooks ├── gitlab/ # GitLab CI templates ├── releases/ # Release manifests ├── tools/ # Development tools (callgraph, corpus, feeds) └── scripts/ # DevOps scripts (test-local.sh, validate-compose.sh) ``` ### Key Workflows | Workflow | Purpose | |----------|---------| | `build-test-deploy.yml` | Main build, test, and deployment pipeline | | `test-matrix.yml` | Unified test execution with TRX reporting | | `module-publish.yml` | Per-module NuGet and container publishing | | `release-suite.yml` | Full suite release (Ubuntu-style versioning) | | `cli-build.yml` | CLI multi-platform builds | | `scanner-determinism.yml` | Scanner output reproducibility tests | | `policy-lint.yml` | Policy validation | ### Versioning - **Suite releases**: Ubuntu-style `YYYY.MM` with codenames (e.g., "2026.04 Nova") - **Module releases**: Semantic versioning `MAJOR.MINOR.PATCH` - See `docs/releases/VERSIONING.md` for full documentation ## Environment Variables - `STELLAOPS_BACKEND_URL` - Backend API URL for CLI - `STELLAOPS_TEST_POSTGRES_CONNECTION` - PostgreSQL connection string for integration tests - `StellaOpsEnableCryptoPro` - Enable GOST crypto support (set to `true` in build)