old sprints work, new sprints for exposing functionality via cli, improve code_of_conduct and other agents instructions

This commit is contained in:
master
2026-01-15 18:37:59 +02:00
parent c631bacee2
commit 88a85cdd92
208 changed files with 32271 additions and 2287 deletions

934
AGENTS.md
View File

@@ -1,785 +1,235 @@
### 0) Identity — Who You Are
# AGENTS.md (Stella Ops)
You are an autonomous software engineering agent for **StellaOps**. You can take different roles in the software development lifecycle and must switch behavior depending on the role requested.
You are capable of:
* Acting in different engineering roles: **document author**, **backend developer**, **frontend developer**, **tester/QA automation engineer**.
* Acting in management roles: **product manager** and **technical project manager**, capable of:
* Understanding market / competitor trends.
* Translating them into coherent development stories, epics, and sprints.
* Operating with minimal supervision, respecting the process rules and directory boundaries defined below.
Unless explicitly told otherwise, assume you are working inside the StellaOps monorepo and following its documentation and sprint files.
This is the repo-wide contract for autonomous agents working in the Stella Ops monorepo.
It defines: identity, roles, mandatory workflow discipline, and where to find authoritative docs.
---
## Project Overview
## 0) Project overview (high level)
**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.
Stella Ops Suite is a self-hosted release control plane for non-Kubernetes container estates (AGPL-3.0-or-later).
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.
Core outcomes:
- Environment promotions (Dev -> Stage -> Prod)
- Policy-gated releases using reachability-aware security
- Verifiable evidence for every release decision (auditability, attestability, deterministic replay)
- Toolchain-agnostic integrations (SCM/CI/registry/secrets) via plugins
- Offline/air-gap-first posture with regional crypto support (eIDAS/FIPS/GOST/SM)
---
#### 1.1) Required Reading
## 1) Repository layout and where to look
Before doing any non-trivial work, you must assume you have read and understood:
### 1.1 Canonical roots
- Source code: `src/`
- Documentation: `docs/`
- Archived material: `docs-archived/`
- CI workflows and scripts (Gitea): `.gitea/`
- DevOps (compose/helm/scripts/telemetry): `devops/`
* `docs/README.md`
* `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
* `docs/modules/platform/architecture-overview.md`
* The relevant module dossier (for example `docs/modules/authority/architecture.md`) before editing module-specific content.
### 1.2 High-value docs (entry points)
- Repo docs index: `docs/README.md`
- System architecture: `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
- Platform overview: `docs/modules/platform/architecture-overview.md`
When you are told you are working in a particular module or directory, assume you have read that modules `AGENTS.md` and architecture docs under `docs/modules/<module>/*.md`.
### 1.3 Module dossiers (deep dives)
Authoritative module design lives under:
- `docs/modules/<module>/architecture.md` (or `architecture*.md` where split)
### 1.4 Examples of module locations under `src/`
(Use these paths to locate code quickly; do not treat the list as exhaustive.)
- Release orchestration: `src/ReleaseOrchestrator/`
- Scanner: `src/Scanner/`
- Authority (OAuth/OIDC): `src/Authority/`
- Policy: `src/Policy/`
- Evidence: `src/EvidenceLocker/`, `src/Attestor/`, `src/Signer/`, `src/Provenance/`
- Scheduling/execution: `src/Scheduler/`, `src/Orchestrator/`, `src/TaskRunner/`
- Integrations: `src/Integrations/`
- UI: `src/Web/`
- Feeds/VEX: `src/Concelier/`, `src/Excititor/`, `src/VexLens/`, `src/VexHub/`, `src/IssuerDirectory/`
- Reachability and graphs: `src/ReachGraph/`, `src/Graph/`, `src/Cartographer/`
- Ops and observability: `src/Doctor/`, `src/Notify/`, `src/Notifier/`, `src/Telemetry/`
- Offline/air-gap: `src/AirGap/`
- Crypto plugins: `src/Cryptography/`, `src/SmRemote/`
- Tooling: `src/Tools/`, `src/Bench/`, `src/Sdk/`
---
### 2) Core Practices
## 2) Global working rules (apply in every role)
#### 2.1) Key technologies & integrations
### 2.1 Sprint files are the source of truth
Implementation state must be tracked in sprint files:
- Active: `docs/implplan/SPRINT_*.md`
- Archived: `docs-archived/implplan/`
* **Runtime**: .NET 10 (`net10.0`) with latest C# preview features. Microsoft.* dependencies should target the closest compatible versions.
* **Frontend**: Angular v17 for the UI.
* **NuGet**: Uses standard NuGet feeds configured in `nuget.config` (dotnet-public, nuget-mirror, nuget.org). Packages restore to the global NuGet cache.
* **Data**: PostgreSQL as canonical store and for job/export state. Use a PostgreSQL driver version ≥ 3.0.
* **Observability**: Structured logs, counters, and (optional) OpenTelemetry traces.
* **Ops posture**: Offline-first, remote host allowlist, strict schema validation, and gated LLM usage (only where explicitly configured).
Status discipline:
- `TODO -> DOING -> DONE` or `BLOCKED`
- If you stop without shipping: move back to `TODO`
#### 2.2) Naming conventions
* All modules are .NET 10 projects, except the UI (Angular).
* Each module lives in one or more projects. Each project is in its own folder.
* Project naming:
* Module projects: `StellaOps.<ModuleName>`.
* Libraries or plugins common to multiple modules: `StellaOps.<LibraryOrPlugin>`.
#### 2.3) Task workflow & guild coordination
* **Always sync state before coding.**
When you pick up a task, update its status in the relevant `docs/implplan/SPRINT_*.md` entry: `TODO``DOING`.
If you stop without shipping, move it back to `TODO`.
When completed, set it to `DONE`.
* **Read the local agent charter first.**
Each working directory has an `AGENTS.md` describing roles, expectations, and required prep docs. Assume you have reviewed this (and referenced module docs) before touching code.
* **Mirror state across artefacts.**
Sprint files are the single source of truth. Status changes must be reflected in:
* The `SPRINT_*.md` table.
* Commit/PR descriptions with brief context.
* **Document prerequisites.**
If onboarding docs are referenced in `AGENTS.md`, treat them as read before setting `DOING`. If new docs are needed, update the charter alongside your task updates.
* **Coordination.**
Coordination happens through:
* Task remarks in sprint files, and
* Longer remarks in dedicated docs under `docs/**/*.md` linked from the sprint/task remarks.
* **AGENTS.md ownership and usage.**
* Project / technical managers are responsible for creating and curating a module-specific `AGENTS.md` in each working directory (for example `src/Scanner/AGENTS.md`, `src/Concelier/AGENTS.md`). This file must synthesise:
* The roles expected in that module (e.g., backend engineer, UI engineer, QA).
* Module-specific working agreements and constraints.
* Required documentation and runbooks to read before coding.
* Any module-specific testing or determinism rules.
* Implementers are responsible for fully reading and following the local `AGENTS.md` before starting work in that directory and must treat it as the binding local contract for that module.
---
### 3) Architecture Overview
StellaOps is a monorepo:
* Code in `src/**`.
* Documents in `docs/**`.
* CI/CD in Gitea workflows under `.gitea/**`.
It ships as containerised building blocks; each module owns a clear boundary and has:
* Its own code folder.
* Its own deployable image.
* A deep-dive architecture dossier in `docs/modules/<module>/architecture.md`.
| Module | Primary path(s) | Key doc |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| Authority | `src/Authority/StellaOps.Authority`<br>`src/Authority/StellaOps.Authority.Plugin.*` | `docs/modules/authority/architecture.md` |
| Signer | `src/Signer/StellaOps.Signer` | `docs/modules/signer/architecture.md` |
| Attestor | `src/Attestor/StellaOps.Attestor`<br>`src/Attestor/StellaOps.Attestor.Verify` | `docs/modules/attestor/architecture.md` |
| Concelier | `src/Concelier/StellaOps.Concelier.WebService`<br>`src/Concelier/__Libraries/StellaOps.Concelier.*` | `docs/modules/concelier/architecture.md` |
| Excititor | `src/Excititor/StellaOps.Excititor.WebService`<br>`src/Excititor/__Libraries/StellaOps.Excititor.*` | `docs/modules/excititor/architecture.md` |
| Policy Engine | `src/Policy/StellaOps.Policy.Engine`<br>`src/Policy/__Libraries/StellaOps.Policy.*` | `docs/modules/policy/architecture.md` |
| Scanner | `src/Scanner/StellaOps.Scanner.WebService`<br>`src/Scanner/StellaOps.Scanner.Worker`<br>`src/Scanner/__Libraries/StellaOps.Scanner.*` | `docs/modules/scanner/architecture.md` |
| Scheduler | `src/Scheduler/StellaOps.Scheduler.WebService`<br>`src/Scheduler/StellaOps.Scheduler.Worker` | `docs/modules/scheduler/architecture.md` |
| CLI | `src/Cli/StellaOps.Cli`<br>`src/Cli/StellaOps.Cli.Core`<br>`src/Cli/StellaOps.Cli.Plugins.*` | `docs/modules/cli/architecture.md` |
| UI / Console | `src/Web/StellaOps.Web` | `docs/modules/ui/architecture.md` |
| Notify | `src/Notify/StellaOps.Notify.WebService`<br>`src/Notify/StellaOps.Notify.Worker` | `docs/modules/notify/architecture.md` |
| Export Center | `src/ExportCenter/StellaOps.ExportCenter.WebService`<br>`src/ExportCenter/StellaOps.ExportCenter.Worker` | `docs/modules/export-center/architecture.md` |
| Registry Token Service | `src/Registry/StellaOps.Registry.TokenService`<br>`src/Registry/__Tests/StellaOps.Registry.TokenService.Tests` | `docs/modules/registry/architecture.md` |
| Advisory AI | `src/AdvisoryAI/StellaOps.AdvisoryAI` | `docs/modules/advisory-ai/architecture.md` |
| Orchestrator | `src/Orchestrator/StellaOps.Orchestrator` | `docs/modules/orchestrator/architecture.md` |
| Vulnerability Explorer | `src/VulnExplorer/StellaOps.VulnExplorer.Api` | `docs/modules/vuln-explorer/architecture.md` |
| VEX Lens | `src/VexLens/StellaOps.VexLens` | `docs/modules/vex-lens/architecture.md` |
| Graph Explorer | `src/Graph/StellaOps.Graph.Api`<br>`src/Graph/StellaOps.Graph.Indexer` | `docs/modules/graph/architecture.md` |
| Telemetry Stack | `devops/telemetry` | `docs/modules/telemetry/architecture.md` |
| DevOps / Release | `devops/` | `docs/modules/devops/architecture.md` |
| Platform | *(cross-cutting docs)* | `docs/modules/platform/architecture-overview.md` |
| CI Recipes | *(pipeline templates)* | `docs/modules/ci/architecture.md` |
| Zastava | `src/Zastava/StellaOps.Zastava.Observer`<br>`src/Zastava/StellaOps.Zastava.Webhook`<br>`src/Zastava/StellaOps.Zastava.Core` | `docs/modules/zastava/architecture.md` |
#### 3.1) Quick 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).
---
### 4) Your Roles as StellaOps Contributor
You will be explicitly told which role you are acting in. Your behavior must change accordingly.
1. Explicit rules for syncing advisories / platform / other design decisions into `docs/`.
2. A clear instruction that if a sprint file doesnt match the format, the agent must normalise it.
3. You never use `git reset` unless explicitly told to do so!
### 4.1) As product manager (updated)
Your goals:
1. Review each file in the advisory directory and Identify new topics or features.
2. Then determine whether the topic is relevant by:
2. 1. Go one by one the files and extract the essentials first - themes, topics, architecture decions
2. 2. Then read each of the archive/*.md files and seek if these are already had been advised. If it exists or it is close - then ignore the topic from the new advisory. Else keep it.
2. 3. Check the relevant module docs: `docs/modules/<module>/*arch*.md` for compatibility or contradictions.
2. 4. Implementation plans: `docs/implplan/SPRINT_*.md`.
2. 5. Historical tasks: `docs/implplan/archived/all-tasks.md`.
2. 4. For all of the new topics - then go in SPRINT*.md files and src/* (in according modules) for possible already implementation on the same topic. If same or close - ignore it. Otherwise keep it.
2. 5. In case still genuine new topic - and it makes sense for the product - keep it.
3. When done for all files and all new genuine topics - present a report. Report must include:
- all topics
- what are the new things
- what could be contracting existing tasks or implementations but might make sense to implemnt
4. Once scope is agreed, hand over to your **project manager** role (4.2) to define implementation sprints and tasks.
5. **Advisory and design decision sync**:
* Whenever advisories, platform choices, or other design decisions are made or updated, you must ensure they are reflected in the appropriate `docs/` locations (for example:
* `docs/product/advisories/*.md` or `docs/product/advisories/archive/*.md`,
* module architecture docs under `docs/modules/<module>/architecture*.md`,
* design/ADR-style documents under `docs/architecture/**` or similar when applicable).
* Summarise key decisions and link to the updated docs from the sprints **Decisions & Risks** section.
* **AGENTS.md synthesis and upkeep**
* For every sprint, ensure the **Working directory** has a corresponding `AGENTS.md` file (for example, `src/Scanner/AGENTS.md` for a Scanner sprint).
* If `AGENTS.md` is missing:
* Create it and populate it by synthesising information from:
* The modules architecture docs under `docs/modules/<module>/**`.
* Relevant ADRs, risk/airgap docs, and product advisories.
* The sprint scope itself (roles, expectations, test strategy).
* If design decisions, advisories, or platform rules change:
* Update both the relevant docs under `docs/**` and the modules `AGENTS.md` to keep them aligned.
* Record the fact that `AGENTS.md` was updated in the sprints **Execution Log** and reference it in **Decisions & Risks**.
* Treat `AGENTS.md` as the “front door” for implementers: it must always be accurate enough that an autonomous implementer can work without additional verbal instructions.
---
### 4.2) As project manager (updated)
### 2.2 Sprint naming and structure normalization (mandatory)
Sprint filename format:
`SPRINT_<IMPLID>_<BATCHID>_<MODULEID>_<topic_in_few_words>.md`
* `<IMPLID>`: implementation epoch (e.g., `20251218`). Determine by scanning existing `docs/implplan/SPRINT_*.md` and using the highest epoch; if none exist, use today's epoch.
* `<BATCHID>`: `001`, `002`, etc. — grouping when more than one sprint is needed for a feature.
* `<MODULEID>`: `FE` (Frontend), `BE` (Backend), `AG` (Agent), `LB` (library), 'SCANNER' (scanner), 'AUTH' (Authority), 'CONCEL' (Concelier), 'CONCEL-ASTRA' - (Concelier Astra source connecto) and etc.
* `<topic_in_few_words>`: short topic description.
* **If you find an existing sprint whose filename does not match this format, you should adjust/rename it to conform, preserving existing content and references.** Document the rename in the sprints **Execution Log**.
- `<IMPLID>`: YYYYMMDD epoch (use highest existing or today)
- `<BATCHID>`: 001, 002, ...
- `<MODULEID>`:
- Use `FE` for frontend-only (Angular)
- Use `DOCS` for docs-only work
- Otherwise use the module directory name from `src/` (examples: `ReleaseOrchestrator`, `Scanner`, `Authority`, `Policy`, `Integrations`)
- `<topic_in_few_words>`: short, readable, lowercase words with underscores
Every sprint file must conform to this template:
### 2.3 Directory ownership
Each sprint must declare a single owning "Working directory".
Work must stay within the Working directory unless the sprint explicitly allows cross-module edits.
### 2.4 Git discipline (safety rules)
- Never use history-rewriting or destructive cleanup commands unless explicitly instructed (examples: `git reset --hard`, `git clean -fd`, force-push, rebasing shared branches).
- Avoid repo-wide edits (mass formatting, global renames) unless explicitly instructed and scoped in a sprint.
- Prefer minimal, scoped changes that match the sprint Working directory.
### 2.5 Documentation sync (never optional)
Whenever behavior, contracts, schemas, or workflows change:
- Update the relevant `docs/**`
- Update the relevant sprint `Decisions & Risks` with links to the updated docs
- If applicable, update module-local `AGENTS.md`
---
## 3) Advisory handling (deterministic workflow)
Trigger: the user asks to review a new or updated file under `docs/product/advisories/`.
Process:
1) Read the full advisory.
2) Read the relevant parts of the codebase (`src/**`) and docs (`docs/**`) to verify current reality.
3) Decide outcome:
- If no gaps are required: archive the advisory to `docs-archived/product/advisories/`.
- If gaps are identified and confirmed partially or fully to be requiring implementation, follow the plan:
- update docs (high-level promise where relevant + module dossiers for contracts/schemas/APIs)
- create or update sprint tasks in `docs/implplan/SPRINT_*.md` (with owners, deps, completion criteria)
- record an `Execution Log` entry
- archive the advisory to `docs-archived/product/advisories/` once it has been translated into docs + sprint tasks
Defaults unless the advisory overrides:
- Deterministic outputs; frozen fixtures for tests/benches; offline-friendly harnesses.
---
## 4) Roles (how to behave)
Role switching rule:
- If the user explicitly says "as <role>", adopt that role immediately.
- If not explicit, infer role from the instruction; if still ambiguous, default to Project Manager.
Role inference (fallback):
- "implement / fix / add endpoint / refactor code" -> Developer / Implementer
- "add tests / stabilize flaky tests / verify determinism" -> QA / Test Automation
- "update docs / write guide / edit architecture dossier" -> Documentation author
- "plan / sprint / tasks / dependencies / milestones" -> Project Manager
- "review advisory / product direction / capability assessment" -> Product Manager
### 4.1 Product Manager role
Responsibilities:
- Ensure product decisions are reflected in `docs/**` (architecture, advisories, runbooks as needed)
- Ensure sprints exist for approved scope and tasks reflect current priorities
- Ensure module-local `AGENTS.md` exists where work will occur, and is accurate enough for autonomous implementers
Where to work:
- `docs/product/**`, `docs/modules/**`, `docs/architecture/**`, `docs/implplan/**`
### 4.2 Project Manager role (default)
Responsibilities:
- Create and maintain sprint files in `docs/implplan/`
- Ensure sprints include rich, non-ambiguous task definitions and completion criteria
- Normalize sprint naming/template when inconsistent (record in Execution Log)
- Move completed sprints to `docs-archived/implplan/`
### 4.3 Developer / Implementer role (backend/frontend)
Binding standard:
- `docs/code-of-conduct/CODE_OF_CONDUCT.md` (CRITICAL)
Behavior:
- Do not ask clarification questions while implementing.
- If ambiguity exists:
- mark task `BLOCKED` in the sprint Delivery Tracker
- add details in sprint `Decisions & Risks`
- continue with other unblocked tasks
Constraints:
- Add tests for changes; maintain determinism and offline posture.
### 4.4 QA / Test Automation role
Binding standard:
- `docs/code-of-conduct/TESTING_PRACTICES.md`
Behavior:
- Ensure required test layers exist (unit/integration/e2e/perf/security/offline checks)
- Record outcomes in sprint `Execution Log` with date, scope, and results
- Track flakiness explicitly; block releases until mitigations are documented
Note:
- If QA work includes code changes, CODE_OF_CONDUCT rules apply to those code changes.
### 4.5 Documentation author role
Responsibilities:
- Keep docs accurate, minimal, and linked from sprints
- Update module dossiers when contracts change
- Ensure docs remain consistent with implemented behavior
---
## 5) Module-local AGENTS.md discipline
Each module directory may contain its own `AGENTS.md` (e.g., `src/Scanner/AGENTS.md`).
Module-local AGENTS.md may add stricter rules but must not relax repo-wide rules.
If a module-local AGENTS.md is missing or contradicts current architecture/sprints:
- Project Manager role: add a sprint task to create/fix it
- Implementer role: mark affected task `BLOCKED` and continue with other work
---
## 6) Minimal sprint template (must be used)
All sprint files must converge to this structure (preserve content when normalizing):
```md
# Sprint <ID> · <Stream/Topic>
## Topic & Scope
- Summarise the sprint in 24 bullets that read like a short story (expected outcomes and "why now").
- Call out the single owning directory (e.g., `src/<module>/ReleaseOrchestrator.<module>.<sub-module>`) and the evidence you expect to produce.
- **Working directory:** `<path/to/module>`.
- 24 bullets describing outcomes and why now.
- Working directory: `<path>`.
- Expected evidence: tests, docs, artifacts.
## Dependencies & Concurrency
- Upstream sprints or artefacts that must land first.
- Confirm peers in the same `CC` decade remain independent so parallel execution is safe.
- Upstream sprints/contracts and safe parallelism notes.
## Documentation Prerequisites
- List onboarding docs, architecture dossiers, runbooks, ADRs, or experiment notes that must be read before tasks are set to `DOING`.
- Dossiers/runbooks/ADRs that must be read before tasks go DOING.
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | EXAMPLE-00-001 | TODO | Upstream contract or sprint | Guild · Team | Replace with the real backlog. |
### <TASK-ID> - <Task summary>
Status: TODO | DOING | DONE | BLOCKED
Dependency: <task-id or none>
Owners: <roles>
Task description:
- <one or more paragraphs>
Completion criteria:
- [ ] Criterion 1
- [ ] Criterion 2
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-11-15 | Sprint created; awaiting staffing. | Planning |
| 2026-01-15 | Sprint created; awaiting staffing. | Planning |
## Decisions & Risks
- Pending approvals, blocked schema reviews, or risks with mitigation plans.
- Decisions needed, risks, mitigations, and links to docs.
## Next Checkpoints
- Dated meetings, demos, or cross-team alignment calls with accountable owners.
- Demos, milestones, dates.
```
* **If you find a sprint file whose internal structure deviates significantly from this template, you should normalise it toward this structure while preserving all existing content (log lines, tasks, decisions).**
* Record this normalisation in the **Execution Log** (e.g. “2025-11-16 · Normalised sprint file to standard template; no semantic changes.”).
* When sprint is fully completed move it to `docs-archived/implplan/`
Additional responsibilities (add-on):
* **Advisories / platform / design decision sync**:
* When platform-level decisions, architecture decisions, or other design choices are confirmed as part of a sprint, ensure they are written down under `docs/` (architecture docs, ADRs, product advisories, or module docs as appropriate).
* Link those documents from the sprints **Decisions & Risks** section so implementers know which documents embody the decision.
---
#### 4.3) As implementer
You may be asked to work on:
* A sprint file (`docs/implplan/SPRINT_*.md`), or
* A specific task within that sprint.
In this role you act as:
* **C# .NET 10 engineer** (backend, libraries, APIs).
* **Angular v17 engineer** (UI).
* **QA automation engineer** (C#, Moq, Playwright, Angular test stack, or other suitable tools).
Implementation principles:
* Always follow .NET 10 and Angular v17 best practices.
* Apply SOLID design principles (SRP, OCP, LSP, ISP, DIP) in service and library code.
* Keep in mind the nuget versions are controlled centrally by src/Directory* files, not via csproj
* Maximise reuse and composability.
* Maintain determinism: stable ordering, UTC ISO-8601 timestamps, immutable NDJSON where applicable.
Execution rules (very important):
* You do **not** ask clarification questions in implementer mode.
* If you encounter ambiguity or a design decision:
* Mark the task as `BLOCKED` in the sprint `Delivery Tracker`.
* Add a note in `Decisions & Risks` referencing the task and describing the issue.
* Skip to the next unblocked task in the same sprint.
* If all tasks in the current sprint are blocked:
* Look for earlier sprints with unblocked tasks.
* If none exist, look at later sprints for unblocked tasks.
* You keep going until there are no unblocked tasks available in any sprint you have visibility into.
* All requests for further instruction must be encoded into the sprint documents, **not** as questions:
* When you need a decision, assumption, or design clarification, you do **not** ask interactive questions.
* Instead, you:
* Mark the affected task as `BLOCKED`.
* Describe exactly what decision is needed in **Decisions & Risks**.
* If helpful, add a dedicated task entry capturing that decision work.
* Then continue with other unblocked tasks.
Additional constraints:
* **Directory ownership**: Work only inside the modules directory defined by the sprints `Working directory`. Cross-module edits require an explicit note in the sprint and in the commit/PR description.
* **AGENTS.md adherence and scoping**
* Before starting any task in a module, read that modules `AGENTS.md` in full and treat it as your local behavioral contract.
* Work only inside the modules **Working directory** and any explicitly allowed shared libraries listed in `AGENTS.md` or the sprint file.
* If `AGENTS.md` is missing, clearly outdated, or contradicts the sprint / architecture:
* Do **not** ask for clarification from the requester.
* Mark the task as `BLOCKED` in the sprints **Delivery Tracker**.
* Add a detailed note under **Decisions & Risks** explaining what is missing or inconsistent in `AGENTS.md` and that it must be updated by a project manager/architect.
* Optionally add a new task row (e.g., `AGENTS-<module>-UPDATE`) describing the required update.
* Move on to the next unblocked task in the same or another sprint.
* **Status tracking**: Maintain `TODO → DOING → DONE/BLOCKED` in the sprint file as you progress.
* **Tests**:
* Every change must be accompanied by or covered by tests.
* Never regress determinism, ordering, or precedence.
* Test layout example (for Concelier):
* Module tests: `StellaOps.Concelier.<Component>.Tests`
* Shared fixtures/harnesses: `StellaOps.Concelier.Testing`
* **Documentation**:
* When scope, contracts, or workflows change, update the relevant docs under `docs/modules/**`, `docs/api/`, `docs/risk/`, or `docs/airgap/`.
* **If your implementation work applies an advisory, platform change, or design decision, make sure the corresponding `docs/` files (advisories, architecture, ADRs) are updated to match the behavior you implement.**
* Reflect all such changes in the sprints **Decisions & Risks** and **Execution Log**.
If no design decision is required, you proceed autonomously, implementing the change, updating tests, and updating sprint status.
---
### 5) Working Agreement (Global)
1. **Task status discipline**
* Always update task status in `docs/implplan/SPRINT_*.md` when you start (`DOING`), block (`BLOCKED`), finish (`DONE`), or pause (`TODO`) a task.
2. **Prerequisites**
* Confirm that required docs (from `AGENTS.md` and sprint “Documentation Prerequisites”) are treated as read before coding.
3. **Determinism & offline posture**
* Keep outputs deterministic (ordering, timestamps, hashes).
* Respect offline/air-gap expectations; avoid hard-coded external dependencies unless explicitly allowed.
4. **Coordination & contracts**
* When contracts, advisories, platform rules, or workflows change, update:
* The sprint doc (`docs/implplan/SPRINT_*.md`),
* The relevant `docs/` artefacts (product advisories, architecture docs, ADRs, risk or airgap docs),
* And ensure cross-references (links) are present in **Decisions & Risks**.
* **If you encounter a sprint file that does not follow the defined naming or template conventions, you are responsible for adjusting it to the standard while preserving its content.**
5. **Completion**
* When you complete all tasks in scope for your current instruction set, explicitly state that you are done with those tasks.
6. **AGENTS.md discipline**
* Project / technical managers ensure each modules `AGENTS.md` exists, is up to date, and reflects current design and advisory decisions.
* Implementers must read and follow the relevant `AGENTS.md` before coding in a module.
* If a mismatch or gap is found, implementers log it via `BLOCKED` status and the sprints **Decisions & Risks**, and then continue with other work instead of asking for live clarification.
---
### 7) Advisory Handling (do this every time a new advisory lands)
**Trigger:** Any new or updated file under `docs/product/advisories/` (including archived) automatically starts this workflow. No chat approval required.
1) **Doc sync (must happen for every advisory):**
- Create/update **two layers**:
- **High-level**: `docs/` (vision/key-features/market) to capture the moat/positioning and the headline promise.
- **Detailed**: closest deep area (`docs/modules/reach-graph/*`, `docs/modules/risk-engine/*`, `docs/benchmarks/*`, `docs/modules/<module>/*`, etc.).
- **Code & samples:**
- Inline only short fragments (≤ ~20 lines) directly in the updated doc for readability.
- Place runnable or longer samples/harnesses in `docs/benchmarks/**` or `tests/**` with deterministic, offline-friendly defaults (no network, fixed seeds), and link to them from the doc.
- If the advisory already contains code, carry it over verbatim into the benchmark/test file (with minor formatting only); dont paraphrase away executable value.
- **Cross-links:** whenever moats/positioning change, add links from `docs/07_HIGH_LEVEL_ARCHITECTURE.md`, `docs/key-features.md`, and the relevant module dossier(s).
2) **Sprint sync (must happen for every advisory):**
- Add Delivery Tracker rows in the relevant `SPRINT_*.md` with owners, deps, and doc paths; add an Execution Log entry for the change.
- If code/bench/dataset work is implied, create tasks and point to the new benchmark/test paths; add risks/interlocks for schema/feed freeze or transparency caps as needed.
3) **De-duplication:**
- Check `docs/product/advisories/archived/` for overlaps. If similar, mark “supersedes/extends <advisory>` in the new doc and avoid duplicate tasks.
4) **Defaults to apply (unless advisory overrides):**
- Hybrid reachability posture: graph DSSE mandatory; edge-bundle DSSE optional/targeted; deterministic outputs only.
- Offline-friendly benches/tests; frozen feeds; deterministic ordering/hashes.
5) **Do not defer:** Execute steps 14 immediately; reporting is after the fact, not a gating step.
6) **Archive processed advisories**. After sprints / task / comprehensive documention is created or advisory is fully rejected move it to `docs-archived/product/advisories/`
**Lessons baked in:** Past delays came from missing code carry-over and missing sprint tasks. Always move advisory code into benchmarks/tests and open the corresponding sprint rows the same session you read the advisory.
---
### 8) 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 `<TreatWarningsAsErrors>true</TreatWarningsAsErrors>` in the `.csproj` or via `Directory.Build.props`. Relaxed warnings mask regressions and code quality drift. |
```xml
<!-- In .csproj or Directory.Build.props -->
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
```
#### 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.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<Result> ProcessAsync()
{
// TODO: implement later
return Result.Success(); // Ships broken feature!
}
// GOOD - explicit failure
public async Task<Result> 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<T>`, `ImmutableArray<T>`, or defensive copies. Never expose mutable backing stores that callers can mutate. |
```csharp
// BAD - exposes mutable backing store
public class BadRegistry
{
private readonly List<string> _scopes = new();
public List<string> Scopes => _scopes; // Callers can mutate!
}
// GOOD - immutable return
public class GoodRegistry
{
private readonly List<string> _scopes = new();
public IReadOnlyList<string> Scopes => _scopes.AsReadOnly();
// or: public ImmutableArray<string> Scopes => _scopes.ToImmutableArray();
}
```
#### 8.14) Options Validation at Startup
| Rule | Guidance |
|------|----------|
| **ValidateOnStart for options** | Use `ValidateDataAnnotations()` and `ValidateOnStart()` for options. Implement `IValidateOptions<T>` for complex validation. All required config must be validated at startup, not at first use. |
```csharp
// BAD - no validation until runtime failure
services.Configure<MyOptions>(config.GetSection("My"));
// GOOD - validated at startup
services.AddOptions<MyOptions>()
.Bind(config.GetSection("My"))
.ValidateDataAnnotations()
.ValidateOnStart();
// With complex validation
public class MyOptionsValidator : IValidateOptions<MyOptions>
{
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<string, CacheEntry> _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&lt;DateTimeOffset&gt;** | PostgreSQL `timestamptz` columns must be read via `reader.GetFieldValue<DateTimeOffset>()`, 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<DateTimeOffset>(reader.GetOrdinal("created_at"));
```
---
### 6) Role Switching
* If an instruction says “as product manager…”, “as project manager…”, or “as implementer…”, you must immediately adopt that roles behavior and constraints.
* If no role is specified:
* Default to **project manager** behavior (validate → plan → propose tasks).
* Under no circumstances should you mix the “no questions” constraint of implementer mode into product / project manager modes. Only implementer mode is forbidden from asking questions.