diff --git a/docs/code-of-conduct/CODE_OF_CONDUCT.md b/docs/code-of-conduct/CODE_OF_CONDUCT.md index 4e512b0ea..81a7bb13d 100644 --- a/docs/code-of-conduct/CODE_OF_CONDUCT.md +++ b/docs/code-of-conduct/CODE_OF_CONDUCT.md @@ -1,679 +1,581 @@ # StellaOps Engineering Code of Conduct -*Technical excellence + safe for change = best-in-class product* +Technical excellence + safe for change = best-in-class product --- -## 0 · Mission and Values +## 0. Mission and operating intent -**StellaOps** is a sovereign, self-hostable release control plane delivering reproducible, auditable, and secure software releases for non-Kubernetes container estates. We are committed to building a **best-in-class product that is safe for change** — where every contribution improves quality, maintainability, and security without regression. +StellaOps is a sovereign, self-hostable release control plane for non-Kubernetes container estates. We ship reproducible, auditable, security-gated releases where every decision is explainable and defensible. -### Our Engineering Pledge +### Engineering pledge (non-negotiable) +Every contribution must improve the product without regressions in: -We pledge to uphold: +1. Correctness (it does what it claims). +2. Safety for change (tests and structure allow refactoring without fear). +3. Determinism (same inputs produce the same outputs for evidence and replay). +4. Security (fail secure; least privilege; cryptographic correctness). +5. Operability (observable, diagnosable, offline/air-gap friendly). -1. **Technical Excellence** — Code that is deterministic, testable, and production-ready from day one. -2. **Safety for Change** — Comprehensive testing, minimal surprise, and zero tolerance for silent failures. -3. **Security by Design** — Input validation, least privilege, cryptographic correctness, and defense in depth. -4. **Maintainability First** — Clear contracts, minimal coupling, immutable outputs, and self-documenting code. -5. **Transparency and Auditability** — Every decision, every release, every change is traceable and reproducible. - -This document codifies the **technical standards** all contributors must follow. Behavioral expectations are covered in [COMMUNITY_CONDUCT.md](./COMMUNITY_CONDUCT.md). +This document is written for humans and autonomous implementers. It is intentionally prescriptive. --- -## 1 · Core Principles +## 1. Scope, authority, and precedence -### 1.1 Quality +### 1.1 Applies to +- All code contributions (C#, TypeScript, Angular, SQL, Dockerfiles, Compose/Helm, CI pipelines, scripts). +- All documentation that defines contracts or operational reality (architecture dossiers, API/CLI references, runbooks, sprint plans). +- All tests and test infrastructure. -Quality is not negotiable. Every line of code must be: - -- **Correct** — Does what it claims, handles errors gracefully, fails fast when assumptions break -- **Tested** — Unit tests for logic, integration tests for contracts, E2E tests for workflows -- **Deterministic** — Same inputs always produce same outputs; no hidden state, no timing dependencies -- **Observable** — Logs structured events, emits metrics, traces execution paths -- **Documented** — Self-explanatory code; architecture decisions recorded; APIs have examples - -**Why it matters**: Quality debt compounds. A shortcut today becomes a week-long incident tomorrow. We build for the long term. +### 1.2 Authority +- This document supersedes informal guidance. +- Module-local `AGENTS.md` files may impose stricter requirements, but may not relax these standards. +- If a rule is unclear, prefer the interpretation that increases determinism, testability, and security. --- -### 1.2 Maintainability +## 2. Mandatory reading (before non-trivial work) -Code is read 10x more than it's written. Optimize for the next engineer: +Before contributing to any module, read: +1. This file (CODE_OF_CONDUCT.md) +2. `docs/README.md` +3. `docs/07_HIGH_LEVEL_ARCHITECTURE.md` +4. `docs/modules/platform/architecture-overview.md` +5. [TESTING_PRACTICES.md](./TESTING_PRACTICES.md) +6. The relevant module dossier: `docs/modules//architecture.md` (or `architecture*.md`) +7. The module-local `AGENTS.md` if present (e.g., `src/Scanner/AGENTS.md`) -- **Clear intent** — Names reveal purpose; functions do one thing; classes have single responsibilities -- **Low coupling** — Modules depend on interfaces, not implementations; changes propagate predictably -- **High cohesion** — Related logic lives together; unrelated logic stays separate -- **Minimal surprise** — Standard patterns over clever tricks; explicit over implicit -- **Refactorable** — Tests enable confident changes; abstractions hide complexity without obscuring behavior - -**Why it matters**: Unmaintainable code slows velocity to zero. We build systems that evolve, not calcify. +Enforcement: changes that contradict documented architecture/contracts will be rejected with a pointer to the violated doc. --- -### 1.3 Security +## 3. Definition of Done (DoD): required evidence -Security is a design constraint, not a feature: +A task/PR is DONE only when the required evidence exists and is linked from the sprint task (or documented explicitly as N/A). -- **Defense in depth** — Multiple layers: input validation, authorization, cryptographic verification, audit trails -- **Least privilege** — Services run with minimal permissions; users see only what they need -- **Fail secure** — Errors deny access; missing config stops startup; invalid crypto rejects requests -- **Cryptographic correctness** — Use vetted libraries; never roll your own crypto; verify all signatures -- **Supply chain integrity** — Pin dependencies; scan for vulnerabilities; generate SBOMs; issue VEX statements -- **Auditability** — Every action logged; every release signed; every decision traceable +Minimum DoD for any change: +- [ ] Tests exist for the change OR a written justification exists in sprint "Decisions & Risks". +- [ ] Determinism: any output participating in evidence/signatures/hashes is deterministic (ordering, timestamps, canonicalization). +- [ ] Docs: contract/workflow/config/schema changes are reflected in `docs/**` and linked from the sprint. +- [ ] Observability: new workflows emit structured logs; core success/failure counters exist. +- [ ] Security: external inputs validated; authorization enforced; secrets not persisted; least privilege respected. +- [ ] Sprint discipline: task status updated (`TODO -> DOING -> DONE` or `BLOCKED`) and completion criteria checked off. -**Why it matters**: Security failures destroy trust. We protect our users' infrastructure and their reputation. +If you cannot satisfy DoD due to constraints, the task is BLOCKED until the constraint is resolved. --- -## 2 · Scope and Authority +## 4. Change-type checklists (select at least one per task/PR) -This Code of Conduct applies to: +These checklists are mandatory. Pick the relevant checklist(s) and satisfy them. -- All code contributions (C#, TypeScript, Angular, SQL, Dockerfiles, Helm charts, CI/CD pipelines) -- All documentation (architecture, API references, runbooks, sprint files) -- All testing artifacts (unit, integration, E2E, performance, security tests) -- All infrastructure-as-code (Terraform, Ansible, Compose, Kubernetes manifests) +### 4.1 Bug fix +- [ ] Repro captured as a failing test first (unless impossible; justify). +- [ ] Fix implemented. +- [ ] Regression test remains and is named for the bug. -**Authority**: This document supersedes informal guidance. When in conflict with external standards, StellaOps rules win. Module-specific `AGENTS.md` files may impose stricter requirements but cannot relax the rules defined here. +### 4.2 New behavior / feature +- [ ] Unit tests cover core logic. +- [ ] Integration tests cover service/API contracts where applicable. +- [ ] Docs updated if user-visible or contract/schema changes occur. +- [ ] Backward-compatibility note recorded if behavior changes. + +### 4.3 New API endpoint / CLI command +- [ ] Request/response validation is explicit. +- [ ] Authz policy is defined and tested. +- [ ] Negative tests: unauthorized, invalid input, boundary values. +- [ ] API/CLI docs updated with at least one example. + +### 4.4 Schema / persistence change +- [ ] Migration present and tested. +- [ ] Indexing considered for new query patterns. +- [ ] Serialization round-trip tests updated/added. +- [ ] Roll-forward behavior documented; rollback constraints noted. + +### 4.5 Security-sensitive change +- [ ] Threat note added in sprint "Decisions & Risks" (what can go wrong + mitigation). +- [ ] Audit events exist where relevant (who/what/when/why). +- [ ] Secrets handling verified (no plaintext persistence). +- [ ] Default posture is deny/fail-secure. --- -## 3 · Mandatory Reading +## 5. Review rejection criteria (hard NACK) -Before contributing to any module, you **must** read and understand: - -1. **This document** — The engineering code of conduct (you're reading it now) -2. [docs/README.md](../README.md) — Project overview and navigation -3. [docs/07_HIGH_LEVEL_ARCHITECTURE.md](../07_HIGH_LEVEL_ARCHITECTURE.md) — System architecture -4. [docs/modules/platform/architecture-overview.md](../modules/platform/architecture-overview.md) — Platform design -5. [TESTING_PRACTICES.md](./TESTING_PRACTICES.md) — Testing requirements and evidence standards -6. The relevant module's architecture dossier (`docs/modules//architecture.md`) -7. The module's `AGENTS.md` if present (e.g., `src/Scanner/AGENTS.md`) - -**Enforcement**: Pull requests that violate documented architecture or module-specific constraints will be rejected with a reference to the violated document. +A PR must be rejected if it introduces any of the following: +- Silent stubs or TODOs without a sprint task reference. +- Nondeterminism in production paths (direct time/ID/random usage). +- Missing validation/authz for new external inputs/endpoints. +- Cross-module dependency creep without a clear interface boundary and documented rationale. +- Network access in tests (except local infrastructure like Testcontainers), or tests that cannot run offline. +- Public APIs exposing mutable collections or mutable internal state. +- Repo-wide refactors unrelated to sprint scope. +- New dependency without justification and supply-chain considerations. --- -## 4 · Code Quality Standards +## 6. Engineering standards (rules + examples) -### 3.1 Compiler Discipline +### 6.1 Compiler and warning discipline +Rule: +- All projects must treat warnings as errors. -**Rule**: All projects must enable `TreatWarningsAsErrors`. +Example: ```xml - true -``` +```` -**Rationale**: Warnings mask regressions and code quality drift. Zero-warning builds are mandatory. +Rationale: + +* Warnings become regressions later. Zero-warning builds are required for safe change. --- -### 3.2 Determinism: Time, IDs, and Randomness +### 6.2 Determinism: time, IDs, randomness -**Rule**: Never use `DateTime.UtcNow`, `DateTimeOffset.UtcNow`, `Guid.NewGuid()`, or `Random.Shared` directly in production code. +Rule: -**Required**: Inject `TimeProvider` and `IGuidGenerator` abstractions. +* Never use `DateTime.UtcNow`, `DateTimeOffset.UtcNow`, `Guid.NewGuid()`, or `Random.Shared` directly in production code. +* Inject `TimeProvider` and an ID generator abstraction (e.g., `IGuidGenerator`). + +Example: ```csharp -// ❌ BAD - nondeterministic, untestable -public class BadService +// [BAD] nondeterministic, hard to test +public sealed class BadService { - public Record CreateRecord() => new Record + public Record CreateRecord() => new() { Id = Guid.NewGuid(), - CreatedAt = DateTimeOffset.UtcNow + CreatedAt = DateTimeOffset.UtcNow, }; } -// ✅ GOOD - injectable, testable, deterministic -public class GoodService(TimeProvider timeProvider, IGuidGenerator guidGenerator) +// [OK] injectable and deterministic under test +public sealed class GoodService(TimeProvider timeProvider, IGuidGenerator guidGenerator) { - public Record CreateRecord() => new Record + public Record CreateRecord() => new() { Id = guidGenerator.NewGuid(), - CreatedAt = timeProvider.GetUtcNow() + CreatedAt = timeProvider.GetUtcNow(), }; } ``` -**Rationale**: Deterministic outputs enable reproducible builds, reliable tests, and cryptographic verification. Nondeterministic code breaks evidence chains. +Rationale: + +* Deterministic behavior is required for reproducible evidence and reliable tests. --- -### 3.3 Culture-Invariant Parsing and Formatting +### 6.3 Culture-invariant parsing and formatting -**Rule**: Always use `CultureInfo.InvariantCulture` for parsing and formatting dates, numbers, percentages, and any string that will be persisted, hashed, or compared. +Rule: + +* Always use `CultureInfo.InvariantCulture` for parsing/formatting any value that is persisted, hashed, compared, or exported. + +Example: ```csharp -// ❌ BAD - culture-sensitive, locale-dependent +// [BAD] culture-sensitive var value = double.Parse(input); var formatted = percentage.ToString("P2"); -// ✅ GOOD - culture-invariant, deterministic +// [OK] deterministic across locales var value = double.Parse(input, CultureInfo.InvariantCulture); var formatted = percentage.ToString("P2", CultureInfo.InvariantCulture); ``` -**Rationale**: Current culture causes nondeterministic behavior across environments. All outputs must be reproducible regardless of locale. +Rationale: + +* Locale-dependent parsing breaks determinism and evidence reproducibility. --- -### 3.4 ASCII-Only Output +### 6.4 ASCII-only output for logs, comments, and exported artifacts -**Rule**: Use ASCII-only characters in comments, output strings, and log messages. No mojibake (`ƒ?`), Unicode glyphs (`✓`, `→`, `バ`), or box-drawing characters. +Rule: + +* Use ASCII-only characters in: + + * log messages, + * comments, + * console output, + * exported artifacts (NDJSON, evidence packets, reports). +* Avoid non-ASCII glyphs in code and examples. + +Exceptions: + +* End-user UI text may be internationalized; if Unicode is required in stored/hashed/exported artifacts, document the rationale and encoding explicitly. + +Example: ```csharp -// ❌ BAD - non-ASCII glyphs -Console.WriteLine("✓ Success → proceeding"); +// [BAD] non-ASCII glyphs in logs +_logger.LogInformation("Success -> proceeding"); -// ✅ GOOD - ASCII only -Console.WriteLine("[OK] Success - proceeding"); +// [OK] ASCII-only +_logger.LogInformation("[OK] Success - proceeding"); ``` -**Exceptions**: When Unicode is **required** (e.g., internationalized user messages), use explicit escapes (`\uXXXX`) and document the rationale. +Rationale: -**Rationale**: Non-ASCII characters break in constrained environments (containers, SSH, logs). ASCII ensures universal readability. +* Non-ASCII breaks in constrained environments and is risky for canonicalization/signatures. --- -### 3.5 Immutable Collection Returns +### 6.5 Immutable collection returns -**Rule**: Public APIs must return `IReadOnlyList`, `ImmutableArray`, or defensive copies. Never expose mutable backing stores. +Rule: + +* Public APIs must return immutable or read-only collections (`IReadOnlyList`, `ImmutableArray`, or defensive copies). +* Never expose mutable backing stores. + +Example: ```csharp -// ❌ BAD - exposes mutable backing store -public class BadRegistry +// [BAD] caller can mutate internal state +public sealed class BadRegistry { private readonly List _scopes = new(); - public List Scopes => _scopes; // Callers can mutate! + public List Scopes => _scopes; } -// ✅ GOOD - immutable return -public class GoodRegistry +// [OK] caller cannot mutate internal state +public sealed class GoodRegistry { private readonly List _scopes = new(); public IReadOnlyList Scopes => _scopes.AsReadOnly(); } ``` -**Rationale**: Mutable returns create hidden coupling and race conditions. Immutability is a safety contract. +Rationale: + +* Immutability is a safety contract that reduces hidden coupling and race conditions. --- -### 3.6 No Silent Stubs +### 6.6 No silent stubs -**Rule**: Placeholder code must throw `NotImplementedException` or return an explicit error status. Never return success from unimplemented paths. +Rule: + +* Unimplemented code must throw `NotImplementedException` (or return an explicit error result). +* Never return success from unimplemented paths. + +Example: ```csharp -// ❌ BAD - silent stub masks missing implementation -public async Task ProcessAsync() -{ - // TODO: implement later - return Result.Success(); // Ships broken feature! -} +// [BAD] ships broken behavior +public Task ProcessAsync() => + Task.FromResult(Result.Success()); -// ✅ GOOD - explicit failure -public async Task ProcessAsync() -{ - throw new NotImplementedException("ProcessAsync not yet implemented. See SPRINT_20251218_001_BE_ReleasePromotion.md"); -} +// [OK] explicit failure with traceability +public Task ProcessAsync() => + throw new NotImplementedException("Not implemented. See sprint task: ."); ``` -**Rationale**: Silent stubs ship broken features. Explicit failures prevent production incidents. +Rationale: + +* Silent stubs create production incidents and false confidence. --- -### 3.7 CancellationToken Propagation +### 6.7 CancellationToken propagation -**Rule**: Always propagate `CancellationToken` through async call chains. Never use `CancellationToken.None` in production code. +Rule: + +* Propagate `CancellationToken` through async call chains. +* Do not use `CancellationToken.None` in production paths. + +Example: ```csharp -// ❌ BAD - ignores cancellation -public async Task ProcessAsync(CancellationToken ct) -{ - await _repository.SaveAsync(data, CancellationToken.None); // Wrong! - await Task.Delay(1000); // Missing ct -} +// [BAD] ignores cancellation +await _repo.SaveAsync(entity, CancellationToken.None); +await Task.Delay(1000); -// ✅ GOOD - propagates cancellation -public async Task ProcessAsync(CancellationToken ct) -{ - await _repository.SaveAsync(data, ct); - await Task.Delay(1000, ct); -} +// [OK] respects cancellation +await _repo.SaveAsync(entity, ct); +await Task.Delay(1000, ct); ``` -**Rationale**: Proper cancellation prevents resource leaks and enables graceful shutdown. +Rationale: + +* Cancellation is required for graceful shutdown and avoiding resource leaks. --- -### 3.8 HttpClient via IHttpClientFactory +### 6.8 HttpClient via IHttpClientFactory -**Rule**: Never instantiate `HttpClient` directly. Use `IHttpClientFactory` with configured timeouts and retry policies. +Rule: + +* Never instantiate `HttpClient` directly. +* Use `IHttpClientFactory` with explicit timeouts and resilience policy. + +Example: ```csharp -// ❌ BAD - direct instantiation -public class BadService -{ - public async Task FetchAsync() - { - using var client = new HttpClient(); // Socket exhaustion risk - await client.GetAsync(url); - } -} +// [BAD] risks socket exhaustion +using var client = new HttpClient(); -// ✅ 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(); +// [OK] factory-managed +var client = httpClientFactory.CreateClient("MyApi"); ``` -**Rationale**: Direct `HttpClient` creation causes socket exhaustion. Factories enable connection pooling and resilience patterns. +Rationale: + +* Factory-based clients are required for production reliability. --- -### 3.9 Bounded Caches with Eviction +### 6.9 Bounded caches with eviction -**Rule**: Do not use `ConcurrentDictionary` or `Dictionary` for caching without eviction policies. +Rule: + +* No unbounded `Dictionary`/`ConcurrentDictionary` caches. +* Use bounded caches with eviction (size limit + TTL), or an external cache with explicit retention. + +Example: ```csharp -// ❌ BAD - unbounded growth +// [BAD] unbounded cache 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) - }); -} +// [OK] bounded cache +private readonly MemoryCache _cache = new(new MemoryCacheOptions { SizeLimit = 10_000 }); ``` -**Rationale**: Unbounded caches cause memory exhaustion in long-running services. Bounded caches with TTL/LRU eviction are mandatory. +Rationale: + +* Unbounded caches eventually crash long-running services. --- -### 3.10 Options Validation at Startup +### 6.10 Options validation at startup -**Rule**: Use `ValidateDataAnnotations()` and `ValidateOnStart()` for all options classes. Implement `IValidateOptions` for complex validation. +Rule: + +* Validate configuration at startup using `ValidateOnStart()`. +* Use `IValidateOptions` for complex validation. + +Example: ```csharp -// ❌ BAD - no validation until runtime failure -services.Configure(config.GetSection("My")); - -// ✅ GOOD - validated at startup services.AddOptions() .Bind(config.GetSection("My")) .ValidateDataAnnotations() .ValidateOnStart(); ``` -**Rationale**: All required config must be validated at startup, not at first use. Fail fast prevents runtime surprises. +Rationale: + +* Fail fast. Do not defer critical config failures to runtime. --- -## 5 · Cryptographic and Security Standards +### 6.11 Explicit paths and roots -### 4.1 DSSE PAE Consistency +Rule: -**Rule**: Use one spec-compliant DSSE PAE helper (`StellaOps.Attestation.DsseHelper`) across the codebase. Never reimplement PAE encoding. +* Do not infer repository or data roots with fragile parent-directory walks. +* Use explicit CLI options and environment variables. + +Rationale: + +* Parent walks break in containers, CI, and offline kits. + +--- + +## 7. Cryptographic and evidence standards + +### 7.1 DSSE PAE consistency + +Rule: + +* Use one shared, spec-compliant DSSE PAE helper across the codebase. +* Never reimplement DSSE PAE. + +Rationale: + +* Crypto encoding drift breaks verification and can create security issues. + +--- + +### 7.2 RFC 8785 JSON canonicalization + +Rule: + +* For digest/signature inputs, use the shared RFC 8785 canonicalizer. +* Do not use relaxed encoders or naming policies for canonical outputs. + +Rationale: + +* Canonical JSON is required for stable signatures and reproducible evidence. + +--- + +### 7.3 Evidence integrity requirements + +Rule: + +* Evidence artifacts must be: + + * content-addressed or hashed, + * reproducible from declared inputs, + * exportable, + * linked from decisions (policy, approvals, deployments) in a traceable chain. + +Rationale: + +* The product promise is audit-grade, verifiable release decisioning. + +--- + +## 8. Data and time correctness + +### 8.1 PostgreSQL timestamptz + +Rule: + +* Store and retrieve timestamps as UTC `DateTimeOffset`. +* Use `reader.GetFieldValue()` for timestamptz. + +Example: ```csharp -// ❌ BAD - custom PAE implementation -var pae = $"DSSEv1 {payloadType.Length} {payloadType} {payload.Length} "; +// [BAD] loses offset +var createdAt = reader.GetDateTime(ordinal); -// ✅ GOOD - use shared helper -var pae = DsseHelper.ComputePreAuthenticationEncoding(payloadType, payload); +// [OK] preserves offset +var createdAt = reader.GetFieldValue(ordinal); ``` -**Rationale**: DSSE v1 requires ASCII decimal lengths and space separators. Reimplementations introduce cryptographic vulnerabilities. +Rationale: + +* Offset loss causes timeline confusion and breaks audit fidelity. --- -### 4.2 RFC 8785 JSON Canonicalization +## 9. Testing requirements (summary) -**Rule**: Use a shared RFC 8785-compliant JSON canonicalizer for digest/signature inputs. Do not use `UnsafeRelaxedJsonEscaping` or `CamelCase` naming for canonical outputs. +All code contributions must include tests. The full policy is in: [TESTING_PRACTICES.md](./TESTING_PRACTICES.md) -```csharp -// ❌ BAD - non-canonical JSON -var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions -{ - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase -}); +Minimum expectations: -// ✅ GOOD - use shared canonicalizer -var canonicalJson = CanonicalJsonSerializer.Serialize(obj); -var digest = ComputeDigest(canonicalJson); -``` +* Unit tests for new logic. +* Integration tests for contracts that cross process boundaries (DB, messaging, storage, HTTP). +* Determinism tests for any artifact that is exported, hashed, or used as evidence. +* Tests must run offline (no live network dependencies). -**Rationale**: RFC 8785 ensures deterministic JSON serialization. Non-canonical JSON breaks signature verification. +Test categorization: + +* Use `[Trait("Category", "Unit")]` for unit tests. +* Use `[Trait("Category", "Integration")]` for integration tests. --- -### 4.3 DateTimeOffset for PostgreSQL timestamptz +## 10. Documentation and sprint discipline -**Rule**: PostgreSQL `timestamptz` columns must be read via `reader.GetFieldValue()`, not `reader.GetDateTime()`. +### 10.1 Docs must match reality -```csharp -// ❌ BAD - loses offset information -var createdAt = reader.GetDateTime(reader.GetOrdinal("created_at")); +Any change affecting: -// ✅ GOOD - preserves offset -var createdAt = reader.GetFieldValue(reader.GetOrdinal("created_at")); -``` +* contracts, +* schemas, +* behavior, +* operations, + must update `docs/**` and be linked from the sprint. -**Rationale**: `GetDateTime()` loses offset information and causes UTC/local confusion. All timestamps must be stored and retrieved as UTC `DateTimeOffset`. +### 10.2 Sprint discipline is mandatory + +* Every task must live in a sprint file in `docs/implplan/`. +* Status must be updated (`TODO -> DOING -> DONE/BLOCKED`). +* Decisions and risks must be recorded in the sprint. --- -### 4.4 Explicit CLI Options for Paths +## 11. Technology stack compliance -**Rule**: Do not derive repository root from `AppContext.BaseDirectory` with parent directory walks. Use explicit CLI options (`--repo-root`) or environment variables. +Mandatory technologies: -```csharp -// ❌ BAD - fragile parent walks -var repoRoot = Path.GetFullPath(Path.Combine( - AppContext.BaseDirectory, "..", "..", "..", "..")); +* Runtime: .NET 10 (`net10.0`) with C# preview where the repo uses it +* Frontend: Angular v17 +* Database: PostgreSQL 16+ +* Testing: xUnit, Testcontainers, Moq -// ✅ GOOD - explicit option with fallback -[Option("--repo-root", Description = "Repository root path")] -public string? RepoRoot { get; set; } +NuGet versioning rules: -public string GetRepoRoot() => - RepoRoot ?? Environment.GetEnvironmentVariable("STELLAOPS_REPO_ROOT") - ?? throw new InvalidOperationException("Repository root not specified. Use --repo-root or set STELLAOPS_REPO_ROOT."); -``` - -**Rationale**: Parent walks break in containerized and CI environments. Explicit paths are mandatory. +* Do not specify package versions in `.csproj`. +* Use `src/Directory.Packages.props` for package versions. +* Prefer latest stable versions unless the repo pins otherwise. --- -## 6 · Testing Requirements +## 12. Supply-chain and dependency security -**All code contributions must include tests.** See [TESTING_PRACTICES.md](./TESTING_PRACTICES.md) for comprehensive guidance. +Rule: -### 5.1 Test Project Requirements +* New dependencies must include: -**Rule**: All production libraries/services must have a corresponding `*.Tests` project covering: -- (a) Happy paths -- (b) Error/edge cases -- (c) Determinism -- (d) Serialization round-trips + * justification (why it is needed), + * operational impact (offline/air-gap behavior), + * security posture (known CVEs and mitigation plan if any). -``` -src/ - Scanner/ - __Libraries/ - StellaOps.Scanner.Core/ - __Tests/ - StellaOps.Scanner.Core.Tests/ <-- Required -``` +Note on CVEs: + +* "No high/critical CVEs" is not a workable standard in real ecosystems. +* The enforceable standard is: + + * no unaddressed high/critical findings without an explicit policy decision record and/or VEX justification, + * documented mitigation or acceptance rationale. --- -### 5.2 Test Categorization +## 13. PR evidence block (required in PR description) -**Rule**: Tag tests correctly: -- `[Trait("Category", "Unit")]` for pure unit tests -- `[Trait("Category", "Integration")]` for tests requiring databases, containers, or network +Every PR must include an evidence block. If not applicable, write "N/A". -```csharp -// ❌ BAD - integration test marked as unit -public class UserRepositoryTests // Uses Testcontainers/Postgres -{ - [Fact] // Missing category - public async Task Save_PersistsUser() { ... } -} +* Sprint task(s): +* Working directory: +* Summary (1-3 bullets): -// ✅ GOOD - correctly categorized -[Trait("Category", "Integration")] -public class UserRepositoryTests -{ - [Fact] - public async Task Save_PersistsUser() { ... } -} + * ... +* Tests added/updated: -[Trait("Category", "Unit")] -public class UserValidatorTests -{ - [Fact] - public void Validate_EmptyEmail_ReturnsFalse() { ... } -} -``` + * Unit: (filters or test names) + * Integration: (filters or test names) + * E2E/Perf/Sec: +* Determinism considerations: -**Rationale**: Unit tests must run fast and offline. Integration tests require infrastructure. Mixing categories breaks CI pipelines. + * +* Docs updated: + + * +* Observability: + + * Logs: + * Metrics: +* Security notes: + + * Input validation: + * Authz: + * Secrets: --- -### 5.3 Test Production Code, Not Reimplementations +## 14. Enforcement and continuous improvement -**Rule**: Test helpers must call production code, not reimplement algorithms. +### 14.1 Enforcement -```csharp -// ❌ BAD - test reimplements production logic -[Fact] -public void Merkle_ComputesCorrectRoot() -{ - var root = TestMerkleHelper.ComputeRoot(leaves); // Drift risk! - Assert.Equal(expected, root); -} +PRs will be rejected if they violate any rule in this document or fail the DoD requirements. -// ✅ GOOD - test exercises production code -[Fact] -public void Merkle_ComputesCorrectRoot() -{ - var root = MerkleTreeBuilder.ComputeRoot(leaves); - Assert.Equal(expected, root); -} -``` +### 14.2 Continuous improvement -**Rationale**: Reimplementations in tests cause test/production drift. Only mock I/O and network boundaries. +This document is living. Improve it by: ---- - -### 5.4 Offline and Deterministic Tests - -**Rule**: All tests must run without network access. Use: -- UTC timestamps -- Fixed seeds -- `CultureInfo.InvariantCulture` -- Injected `TimeProvider` and `IGuidGenerator` - -**Rationale**: Network-dependent tests are flaky and break in air-gapped environments. Deterministic tests are reproducible. - ---- - -## 7 · Architecture and Design Principles - -### 6.1 SOLID Principles - -All service and library code must follow: - -1. **Single Responsibility Principle (SRP)** — One class, one reason to change -2. **Open/Closed Principle (OCP)** — Open for extension, closed for modification -3. **Liskov Substitution Principle (LSP)** — Subtypes must be substitutable for base types -4. **Interface Segregation Principle (ISP)** — Clients should not depend on interfaces they don't use -5. **Dependency Inversion Principle (DIP)** — Depend on abstractions, not concretions - ---- - -### 6.2 Directory Ownership - -**Rule**: Work only inside the module's directory defined by the sprint's "Working directory". Cross-module edits require explicit approval and documentation. - -**Example**: -- Sprint scope: `src/Scanner/` -- Allowed: Edits to `StellaOps.Scanner.*` projects -- Forbidden: Edits to `src/Concelier/` without explicit approval - -**Rationale**: Directory boundaries enforce module isolation and prevent unintended coupling. - ---- - -### 6.3 No Backup Files in Source - -**Rule**: Add backup patterns to `.gitignore` and remove stray artifacts during code review. - -```gitignore -*.Backup.tmp -*.bak -*.orig -*~ -``` - -**Rationale**: Backup files pollute the repository and create confusion. - ---- - -## 8 · Documentation Standards - -### 7.1 Required Documentation - -Every change must update: - -1. **Module architecture docs** (`docs/modules//architecture.md`) -2. **API references** (`docs/api/`) -3. **Sprint files** (`docs/implplan/SPRINT_*.md`) -4. **Risk/airgap docs** if applicable (`docs/risk/`, `docs/airgap/`) - ---- - -### 7.2 Sprint File Discipline - -**Rule**: Always update task status in `docs/implplan/SPRINT_*.md`: -- `TODO` → `DOING` → `DONE` / `BLOCKED` - -Sprint files are the single source of truth for project state. - ---- - -## 9 · Security and Hardening - -### 8.1 Input Validation - -**Rule**: All external inputs (HTTP requests, CLI arguments, file uploads, database queries) must be validated and sanitized. - -**Required**: -- Use `[Required]`, `[Range]`, `[RegularExpression]` attributes on DTOs -- Implement `IValidateOptions` for complex validation -- Reject unexpected inputs with explicit error messages - ---- - -### 8.2 Least Privilege - -**Rule**: Services must run with minimal permissions: -- Database users: read-only where possible -- File system: restrict to required directories -- Network: allowlist remote hosts - ---- - -### 8.3 Dependency Security - -**Enforcement**: PRs introducing new dependencies must include: -- SBOM entry -- VEX statement if vulnerabilities exist -- Justification for the dependency - ---- - -## 10 · Technology Stack Compliance - -### 9.1 Mandatory Technologies - -- **Runtime**: .NET 10 (`net10.0`) with latest C# preview features -- **Frontend**: Angular v17 -- **Database**: PostgreSQL ≥16 -- **Testing**: xUnit, Testcontainers, Moq -- **NuGet**: Standard feeds configured in `nuget.config`. Always strive to use latest stable verison of dependencies. Never specify versions on nugets on the csproj files. Use src/Directory.Packages.props to specify versions. - ---- - -### 9.2 Naming Conventions - -- Module projects: `StellaOps.` -- Libraries: `StellaOps.` -- Tests: `StellaOps..Tests` - ---- - -## 11 · Enforcement and Compliance - -### 10.1 Pull Request Requirements - -All PRs must: - -1. Pass all unit and integration tests -2. Pass determinism checks -3. Include test coverage for new code -4. Update relevant documentation -5. Follow sprint file discipline -6. Pass security scans (no high/critical CVEs) - ---- - -### 10.2 Rejection Criteria - -PRs will be **rejected** if they: - -- Violate any rule in this document -- Introduce compiler warnings -- Fail tests -- Lack required documentation -- Contain silent stubs or nondeterministic code - ---- - -### 10.3 Continuous Improvement - -This document is a **living standard**. Contributors are encouraged to: - -- Propose improvements via PRs -- Document new patterns in module-specific `AGENTS.md` files -- Share lessons learned in sprint retrospectives - ---- - -## 12 · Attribution and License - -This Code of Conduct incorporates engineering standards from: - -- **AGENTS.md** — Autonomous engineering workflows -- **CLAUDE.md** — Claude Code integration guidance -- **TESTING_PRACTICES.md** — Testing and evidence standards - -Copyright © 2025 StellaOps Contributors -Licensed under [AGPL-3.0-or-later](../../LICENSE) - ---- - -**Last updated**: 2026-01-15 -**Next review**: 2026-04-15 +* proposing new rules when recurring defects appear, +* documenting new patterns in module dossiers and module-local `AGENTS.md`, +* adding tests that prevent regressions.