diff --git a/.github/AGENTS.md b/.github/AGENTS.md index 9a470cea..7c0a2f6d 100644 --- a/.github/AGENTS.md +++ b/.github/AGENTS.md @@ -27,7 +27,7 @@ Always run before committing: `pnpm lint && pnpm test && pnpm verify:gha` | SDK | Path | Build | Test | |-----|------|-------|------| | .NET | `src/sdks/dotnet/` | `dotnet build src/sdks/dotnet/Envilder.sln` | `dotnet test tests/sdks/dotnet/` | -| Python | `src/sdks/python/` | — | `make test-sdk-python` (requires `uv`, Docker) | +| Python | `src/sdks/python/` | n/a | `make test-sdk-python` (requires `uv`, Docker) | | Node.js | `src/sdks/nodejs/` | `cd src/sdks/nodejs && pnpm build` | `cd tests/sdks/nodejs && pnpm vitest run` | ## Project Structure @@ -47,11 +47,11 @@ e2e/ End-to-end tests (TestContainers) ## Gotchas -- After any code change touching CLI or GHA, run `pnpm build:gha` — CI will +- After any code change touching CLI or GHA, run `pnpm build:gha`: CI will reject stale bundles via `pnpm verify:gha`. - `pnpm format` **writes** files (Biome --write). Use `pnpm format:check` for validation only. -- SDKs are independent — they share the map-file format but have zero code +- SDKs are independent: they share the map-file format but have zero code dependency on the TypeScript core. - E2E tests require Docker running (LocalStack + Lowkey Vault containers). diff --git a/.github/agents/code-reviewer.agent.md b/.github/agents/code-reviewer.agent.md index f09ede1e..d2fc0630 100644 --- a/.github/agents/code-reviewer.agent.md +++ b/.github/agents/code-reviewer.agent.md @@ -11,7 +11,7 @@ argument-hint: "PR, commit range, or files to review" user-invocable: true --- -# Code Reviewer — Multi-Perspective Analysis +# Code Reviewer: Multi-Perspective Analysis You are the code-review coordinator for the Envilder repository. @@ -33,21 +33,21 @@ Load these skills for analysis criteria: ## Workflow -1. **Identify scope** — list changed files from PR, commit range, or user input -2. **Check ADRs** — read `docs/adr/` for decisions that apply to the changed area +1. **Identify scope**: list changed files from PR, commit range, or user input +2. **Check ADRs**: read `docs/adr/` for decisions that apply to the changed area 3. **Run 5 perspectives** in parallel (see `code-review-perspectives` skill) -4. **Synthesize** — merge, deduplicate, assign severity, order by priority -5. **Verify** — run tests, linter, formatter to confirm findings -6. **Report** — structured output per the skill's format +4. **Synthesize**: merge, deduplicate, assign severity, order by priority +5. **Verify**: run tests, linter, formatter to confirm findings +6. **Report**: structured output per the skill's format 7. **Delegate** fixes when user approves ## Verification After analysis, confirm findings: -1. `pnpm test` — test suite status -2. `biome check && tsc --noEmit` — lint (no modifications) -3. `pnpm format:check` — formatting (no modifications) +1. `pnpm test`: test suite status +2. `biome check && tsc --noEmit`: lint (no modifications) +3. `pnpm format:check`: formatting (no modifications) 4. Browser/Playwright for website changes 5. Stack-specific: `dotnet build`/`dotnet test`, `make check-sdk-python` @@ -73,7 +73,7 @@ When user requests full review with fixes: ## Constraints -- **Never modify files** — read-only analysis only +- **Never modify files**: read-only analysis only - Do not report style-only nits unless they block quality gates - State assumptions explicitly - When delegating, re-verify after delegate completes diff --git a/.github/agents/content-designer.agent.md b/.github/agents/content-designer.agent.md index 9961a73c..ed5a1dc9 100644 --- a/.github/agents/content-designer.agent.md +++ b/.github/agents/content-designer.agent.md @@ -12,7 +12,7 @@ agents: ['Code Reviewer', 'TDD Coach', 'Explore'] user-invocable: true --- -# Content Designer — Website, Documentation & i18n Specialist +# Content Designer: Website, Documentation & i18n Specialist You are a senior content and UI specialist for the Envilder project. You own **all non-behavioral content**: the website, documentation, changelogs, READMEs, @@ -23,21 +23,21 @@ linguistic correctness across all locales. ### ✅ CAN modify -- `src/website/` — Astro components, pages, CSS, layouts, i18n files -- `docs/` — All documentation files, changelogs, architecture docs +- `src/website/`: Astro components, pages, CSS, layouts, i18n files +- `docs/`: All documentation files, changelogs, architecture docs - `README.md`, `github-action/README.md`, `src/sdks/*/README.md` - `ROADMAP.md`, `CONTRIBUTING.md` -- `examples/` — Example code and README files -- `.github/skills/`, `.github/instructions/` — Copilot customization +- `examples/`: Example code and README files +- `.github/skills/`, `.github/instructions/`: Copilot customization ### ❌ CANNOT modify -- `src/envilder/` — CLI and GHA application code -- `src/sdks/` (except README.md) — SDK implementation code -- `src/iac/` — Infrastructure as Code -- `tests/` — Test logic (can read for verification, cannot edit) -- `e2e/` — End-to-end tests -- `package.json`, `tsconfig.json`, `vite.config.ts` — Build config +- `src/envilder/`: CLI and GHA application code +- `src/sdks/` (except README.md): SDK implementation code +- `src/iac/`: Infrastructure as Code +- `tests/`: Test logic (can read for verification, cannot edit) +- `e2e/`: End-to-end tests +- `package.json`, `tsconfig.json`, `vite.config.ts`: Build config If a task requires code changes outside scope, delegate to the appropriate agent. @@ -55,33 +55,33 @@ Load these skills before starting work: | `doc-sync` | Cross-surface drift audit | | `sdk-release-checklist` | Adding/updating SDK on website | -## Workflow — Website Changes +## Workflow: Website Changes -1. **Start dev server** — `cd src/website && pnpm dev` (skip if running) -2. **Open browser** — Navigate to `http://localhost:4322/` via Playwright -3. **Read first** — Understand existing structure, CSS classes, i18n keys -4. **Build mobile-first** — Start mobile, add tablet/desktop media queries -5. **Validate** — 3-breakpoint Playwright validation (both themes) -6. **i18n-proof** — Add keys to all locales, verify rendering per locale -7. **Build check** — `cd src/website && pnpm build` +1. **Start dev server**: `cd src/website && pnpm dev` (skip if running) +2. **Open browser**: Navigate to `http://localhost:4322/` via Playwright +3. **Read first**: Understand existing structure, CSS classes, i18n keys +4. **Build mobile-first**: Start mobile, add tablet/desktop media queries +5. **Validate**: 3-breakpoint Playwright validation (both themes) +6. **i18n-proof**: Add keys to all locales, verify rendering per locale +7. **Build check**: `cd src/website && pnpm build` -## Workflow — Documentation Changes +## Workflow: Documentation Changes 1. **Identify** what changed (feature/fix/dependency/workflow) 2. **Locate** impacted documentation (use `doc-maintenance` skill for scope) 3. **Update** smallest set of sections needed for correctness -4. **Cross-check** consistency — use `doc-sync` skill if scope is wide -5. **Validate** — `pnpm lint` +4. **Cross-check** consistency: use `doc-sync` skill if scope is wide +5. **Validate**: `pnpm lint` -## Workflow — i18n Audit +## Workflow: i18n Audit -1. **Discover locales** — scan `src/website/src/i18n/` for `*.ts` files +1. **Discover locales**: scan `src/website/src/i18n/` for `*.ts` files (excluding `types.ts` and `utils.ts`) 2. **Read** `types.ts` to understand key structure 3. **Browse** all pages in each locale via Playwright 4. **Scan** components for hardcoded strings 5. **Report** issues in structured table format -6. **Fix** — update locale files, add missing keys, rebuild +6. **Fix**: update locale files, add missing keys, rebuild ## i18n Audit Report Format @@ -110,7 +110,7 @@ Product names, CLI flags, code tokens, and acronyms stay in English: | Trigger | Delegate to | Why | |---------|-------------|-----| -| Task requires source code changes | `@TDD Coach` | Outside scope — handles via TDD | +| Task requires source code changes | `@TDD Coach` | Outside scope: handles via TDD | | Need to verify documented behavior matches code | `@Code Reviewer` | Read-only analysis | | CSS/layout needs structural refactoring | Apply directly | Use `code-refactoring` skill | | Website JS/TS logic has a bug | `@TDD Coach` | Investigate + fix via TDD | diff --git a/.github/agents/pr-resolver.agent.md b/.github/agents/pr-resolver.agent.md index a300e665..9369f520 100644 --- a/.github/agents/pr-resolver.agent.md +++ b/.github/agents/pr-resolver.agent.md @@ -14,10 +14,10 @@ argument-hint: "PR comments or files to address" user-invocable: true --- -# PR Resolver — Review Feedback Handler +# PR Resolver: Review Feedback Handler You resolve pull request review comments with minimal, correct, verified changes. -**Every comment gets a reply on GitHub — no exceptions.** +**Every comment gets a reply on GitHub: no exceptions.** ## Workflow @@ -25,12 +25,12 @@ For each review comment on the active PR: 1. **Load comments** via `github-pull-request_getPullRequestComments` or from user-provided text. 2. **Classify** the comment (see Classification below). -3. **Present to user** — for every comment, show: +3. **Present to user**: for every comment, show: - The reviewer's comment (quoted) - The affected file and line - Your proposed action (fix, skip, delegate, or answer) - A brief explanation of the change you plan to make -4. **Wait for user approval** — do NOT proceed until the user explicitly +4. **Wait for user approval**: do NOT proceed until the user explicitly confirms. The user may approve, reject, or request an alternative. **This step is mandatory and must never be skipped.** 5. **Act** on the comment (only after approval): @@ -53,7 +53,7 @@ For each review comment on the active PR: | **Documentation gap** | Update relevant docs | | **Refactoring request** | Apply using `code-refactoring` skill | | **Test coverage request** | Delegate to `@TDD Coach` | -| **Out of scope / disagree** | Skip — reply explaining why | +| **Out of scope / disagree** | Skip: reply explaining why | ## Commit-Per-Fix Protocol @@ -72,10 +72,10 @@ Each addressed comment produces **its own commit** before replying: This keeps the PR history reviewable and each fix traceable to its comment. -## GitHub Reply Protocol — Mandatory for ALL Comments +## GitHub Reply Protocol: Mandatory for ALL Comments **Every single comment MUST receive a reply on GitHub**, regardless of outcome. -Do not just summarize in the chat — reply directly in the review thread. +Do not just summarize in the chat: reply directly in the review thread. ### Addressed Comments @@ -94,7 +94,7 @@ Example reply: **Files:** `src/core/domain/ports/ISecretProvider.ts:12` **Commit:** [`a1b2c3d`](https://github.com/owner/repo/commit/a1b2c3d) -**Evidence:** `pnpm lint` — ✓, `pnpm test` — ✓ +**Evidence:** `pnpm lint`: ✓, `pnpm test`: ✓ ``` ### Skipped / Ignored Comments @@ -121,7 +121,7 @@ Reply with the answer directly, referencing code evidence: ```markdown **Answer.** The `$config` section is parsed in `MapFileParser.ts:45-60` and merged with CLI flags in `ContainerConfiguration.ts:30`. The CLI flag always -takes precedence — see the spread order at line 35. +takes precedence: see the spread order at line 35. ``` ## Markdown Formatting Rules @@ -191,12 +191,12 @@ After processing all comments, output a summary in the chat: **GitHub Reply:** ✓ posted ### Comment: "{summary}" -**Action:** Skipped — {reason} +**Action:** Skipped: {reason} **GitHub Reply:** ✓ posted ## Validation -- `pnpm lint` — ✓ -- `pnpm test` — ✓ +- `pnpm lint`: ✓ +- `pnpm test`: ✓ ## Open Items - {blockers, assumptions, or reviewer clarifications needed} @@ -209,11 +209,11 @@ After processing all comments, output a summary in the chat: change, commit, or GitHub reply. This rule has no exceptions. - **Always respond and write PR comments in English**, regardless of user's language. -- **EVERY comment gets a GitHub reply — NO EXCEPTIONS.** Whether you fix it, +- **EVERY comment gets a GitHub reply: NO EXCEPTIONS.** Whether you fix it, skip it, or answer it, you MUST post a reply in the review thread on GitHub. A comment without a GitHub reply is a bug in your workflow. Never consider a comment "done" until the reply is posted and the thread is resolved. -- **All replies use Markdown formatting** — no plain text. +- **All replies use Markdown formatting**: no plain text. - **Commit each fix individually** before replying to the comment. - Do not make unrelated refactors while resolving comments. - Do not claim resolved without concrete evidence. @@ -253,14 +253,14 @@ When multiple review threads point to the same file/area (e.g., 4 threads on `DemoVideo.astro`), reply with the full resolution to the **first** thread only. For the remaining threads, reply with: -> Same fix — see reply above. **Commit:** [``]() +> Same fix: see reply above. **Commit:** [``]() Then resolve all threads. This avoids duplicate walls of text in the PR conversation view. ### NEVER use `gh pr comment` for review replies -`gh pr comment` creates a **top-level PR comment** — it does NOT reply inside a +`gh pr comment` creates a **top-level PR comment**: it does NOT reply inside a review thread. This is ALWAYS wrong when responding to review feedback. **Correct workflow (GraphQL):** diff --git a/.github/agents/tdd-coach.agent.md b/.github/agents/tdd-coach.agent.md index 818a392a..5f4ae248 100644 --- a/.github/agents/tdd-coach.agent.md +++ b/.github/agents/tdd-coach.agent.md @@ -10,7 +10,7 @@ argument-hint: "feature, requirement, or behavior to implement" user-invocable: true --- -# TDD Coach — Red-Green-Refactor Coordinator +# TDD Coach: Red-Green-Refactor Coordinator You guide the user through Test-Driven Development by planning requirements, delegating code writing to specialized worker subagents, and tracking cycle @@ -55,7 +55,7 @@ Before planning tests, evaluate the design: - **Deep modules:** Can the interface be smaller? Fewer methods, simpler params, more complexity hidden inside? - **Deletion test:** Would removing any planned module just move complexity to - callers? If yes, it's earning its keep. If not, it's a pass-through — eliminate it. + callers? If yes, it's earning its keep. If not, it's a pass-through: eliminate it. - **Interface testability:** Does each module (1) accept deps rather than creating them, (2) return results rather than side-effecting, (3) have small surface area? @@ -69,7 +69,7 @@ Present a numbered plan: | 1 | Should_{X}_When_{Y} | Unit | {why} | | 2 | Should_{X}_When_{Y} | Unit | {why} | -Approach: {inside-out / outside-in} — {rationale} +Approach: {inside-out / outside-in}: {rationale} ``` Wait for user confirmation before proceeding. @@ -103,8 +103,8 @@ After each cycle, report: ```text ## Cycle {N} Complete -**RED:** {test_file}::{test_name} — fails ✓ -**GREEN:** {production_file} — {what changed} — passes ✓ +**RED:** {test_file}::{test_name}: fails ✓ +**GREEN:** {production_file}: {what changed}: passes ✓ **REFACTOR:** {what improved, or "no changes needed"} Remaining: {N} cycles @@ -123,7 +123,7 @@ Remaining: {N} cycles ## Conventions - Test naming: `Should__When_` -- AAA markers: `// Arrange`, `// Act`, `// Assert` — each at most once per test +- AAA markers: `// Arrange`, `// Act`, `// Assert`: each at most once per test - Mock at port boundaries using `vi.fn()` - Use `pnpm test` for verification diff --git a/.github/agents/tdd-green.agent.md b/.github/agents/tdd-green.agent.md index 73a9b573..5609f152 100644 --- a/.github/agents/tdd-green.agent.md +++ b/.github/agents/tdd-green.agent.md @@ -7,7 +7,7 @@ tools: [read, search, edit, execute] user-invocable: false --- -# TDD Green — Minimal Implementation +# TDD Green: Minimal Implementation You write the minimum production code to make the failing test pass. @@ -24,8 +24,8 @@ You write the minimum production code to make the failing test pass. - Follow hexagonal architecture boundaries - Use Command/Handler pattern when adding new application behavior - Register new services in `types.ts` and `Startup.ts` if needed - - Inject ports via `@inject(TYPES.X)` — never instantiate infrastructure directly -3. **Run** `pnpm test` — the previously failing test must now pass. + - Inject ports via `@inject(TYPES.X)`: never instantiate infrastructure directly +3. **Run** `pnpm test`: the previously failing test must now pass. 4. **Run** `pnpm lint` to ensure no formatting issues. 5. **Verify** no other tests broke. @@ -36,13 +36,13 @@ You write the minimum production code to make the failing test pass. **Production file(s):** {paths} **What changed:** {concise description} -**Test status:** {test_name} — PASSES ✓ +**Test status:** {test_name}: PASSES ✓ **All tests:** {N} passed, 0 failed ``` ## Rules -- Write **only** what the test requires — no speculative features -- Do not refactor, rename, or reorganize — that's the Refactor phase -- Do not add tests — that's the Red phase +- Write **only** what the test requires: no speculative features +- Do not refactor, rename, or reorganize: that's the Refactor phase +- Do not add tests: that's the Red phase - If the fix requires changes across layers, respect architecture boundaries diff --git a/.github/agents/tdd-red.agent.md b/.github/agents/tdd-red.agent.md index df88aa61..82ae68da 100644 --- a/.github/agents/tdd-red.agent.md +++ b/.github/agents/tdd-red.agent.md @@ -7,7 +7,7 @@ tools: [read, search, edit, execute] user-invocable: false --- -# TDD Red — Write One Failing Test +# TDD Red: Write One Failing Test You write a single failing test that defines the expected behavior. @@ -24,12 +24,12 @@ You write a single failing test that defines the expected behavior. Create it if it doesn't exist. 2. **Write one test** following conventions: - Name: `Should__When_` - - Structure: `// Arrange`, `// Act`, `// Assert` — each exactly once + - Structure: `// Arrange`, `// Act`, `// Assert`: each exactly once - Mock ports with `vi.fn()` for unit tests - Use `sut` for subject under test, `actual` for result 3. **Run** `pnpm test` and capture output. 4. **Verify failure:** The test must fail because the behavior is not yet - implemented — not because of a syntax error or wrong import. + implemented: not because of a syntax error or wrong import. 5. **Run** `pnpm lint` to ensure no formatting issues. ## Output (to coordinator) @@ -49,15 +49,15 @@ You write a single failing test that defines the expected behavior. Before reporting back: - [ ] Test describes behavior (WHAT), not implementation (HOW) -- [ ] Test uses public interface only — no internal method calls +- [ ] Test uses public interface only: no internal method calls - [ ] Test would survive an internal refactor without breaking - [ ] Mocks are preferably at system boundaries (ports: ISecretProvider, - IVariableStore, ILogger) — mocking own classes is acceptable when it + IVariableStore, ILogger): mocking own classes is acceptable when it avoids complex Arrange setup without losing behavioral confidence ## Rules - Write **exactly one** test per invocation -- The test must **fail** — if it passes, the behavior already exists +- The test must **fail**: if it passes, the behavior already exists - Do not write any production code - Do not modify existing tests unless the coordinator explicitly requests it diff --git a/.github/agents/tdd-refactor.agent.md b/.github/agents/tdd-refactor.agent.md index af12ca2b..aba1ef1b 100644 --- a/.github/agents/tdd-refactor.agent.md +++ b/.github/agents/tdd-refactor.agent.md @@ -7,7 +7,7 @@ tools: [read, search, edit, execute] user-invocable: false --- -# TDD Refactor — Improve Structure +# TDD Refactor: Improve Structure You improve production and test code structure while ensuring all tests remain green. @@ -24,7 +24,7 @@ green. - Improve naming clarity - Extract helper methods if warranted - Simplify conditional logic - - **Shallow modules** — interface nearly as complex as implementation. + - **Shallow modules**: interface nearly as complex as implementation. Apply deletion test: if removing it concentrates complexity, keep it. If removing it just moves logic back to callers without loss, inline it. - Ensure test readability (clear AAA sections, descriptive names) @@ -46,11 +46,11 @@ green. ## Rules -- **Never change behavior** — only improve structure +- **Never change behavior**: only improve structure - **Keep CRAP below 6.** See `code-quality-crap` skill for formula and thresholds. Extract complex branches into smaller methods. If the threshold cannot be met without adding tests, flag the coordinator to start a new Red cycle for coverage. - Run tests after **every** change, not just at the end - If unsure whether a change preserves behavior, skip it -- Do not add new tests or features — that starts a new cycle +- Do not add new tests or features: that starts a new cycle diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index e7cfae91..b026dd60 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -6,9 +6,9 @@ Envilder is a **multi-runtime secret management platform** that securely centralizes environment variables from AWS SSM Parameter Store or Azure Key Vault. The product has two halves: -1. **TypeScript core** — CLI + GitHub Action for pulling/pushing secrets (Hexagonal Architecture, InversifyJS DI) -2. **Runtime SDKs** — Independent libraries (.NET, Python, more planned) - that load secrets directly into app processes at startup — no `.env` +1. **TypeScript core**: CLI + GitHub Action for pulling/pushing secrets (Hexagonal Architecture, InversifyJS DI) +2. **Runtime SDKs**: Independent libraries (.NET, Python, more planned) + that load secrets directly into app processes at startup: no `.env` files, no intermediaries All components share the **map-file format** as the universal contract (JSON, @@ -60,7 +60,7 @@ testability and modularity. **Container Setup Pattern** (see `src/envilder/apps/shared/ContainerConfiguration.ts`): ```typescript -// Provider selection via factory registry — NOT inline construction +// Provider selection via factory registry: NOT inline construction const providerFactories: Record = { aws: (config) => createAwsSecretProvider(config), azure: (config, options) => createAzureSecretProvider(config, options), @@ -87,18 +87,18 @@ object passed to `configureInfrastructureServices()`. CLI flags override **Development**: -- `pnpm build` — TypeScript compilation -- `pnpm build:gha` — Bundle GitHub Action with `@vercel/ncc` into `github-action/dist/index.js` -- `pnpm verify:gha` — Verify GHA bundle is up-to-date (fails if dist is stale) -- `pnpm local:install` — Build + pack + install globally for local testing -- `pnpm local:test-run` — Run CLI against `e2e/sample/envilder.json` +- `pnpm build`: TypeScript compilation +- `pnpm build:gha`: Bundle GitHub Action with `@vercel/ncc` into `github-action/dist/index.js` +- `pnpm verify:gha`: Verify GHA bundle is up-to-date (fails if dist is stale) +- `pnpm local:install`: Build + pack + install globally for local testing +- `pnpm local:test-run`: Run CLI against `e2e/sample/envilder.json` **Quality**: -- `pnpm test` — Vitest with coverage (v8 provider, outputs to `coverage/`) -- `pnpm test:ci` — Adds JUnit reporter for CI pipelines -- `pnpm lint` — Runs Secretlint (credential detection), Biome (format/lint), and `tsc --noEmit` -- `pnpm format` — Auto-format with Biome +- `pnpm test`: Vitest with coverage (v8 provider, outputs to `coverage/`) +- `pnpm test:ci`: Adds JUnit reporter for CI pipelines +- `pnpm lint`: Runs Secretlint (credential detection), Biome (format/lint), and `tsc --noEmit` +- `pnpm format`: Auto-format with Biome **E2E Tests**: Located in `e2e/`, use real AWS SSM via LocalStack and Azure Key Vault via Lowkey Vault (both via TestContainers). Run `pnpm build` + `pack-and-install.ts` before E2E. @@ -131,7 +131,7 @@ Example (PushSingle): ### GitHub Action Constraints -- **Pull-only**: GHA only supports pull mode (no push) — see `Gha.ts` line 20 +- **Pull-only**: GHA only supports pull mode (no push): see `Gha.ts` line 20 - **Input convention**: GitHub passes inputs as `INPUT_` env vars - **Bundle requirement**: After any code change, run `pnpm build:gha` to update `dist/index.js` @@ -140,7 +140,7 @@ Example (PushSingle): - **Framework**: Vitest with built-in mocking (`vi.fn()`, `vi.mock()`) - **E2E Testing**: TestContainers with `@testcontainers/localstack` for real AWS SSM integration - **Naming**: Use `Should__When_` pattern (e.g., `Should_ThrowError_When_SSMParameterIsNotFound`) -- **Structure**: Follow AAA (Arrange-Act-Assert) pattern with explicit comment markers — +- **Structure**: Follow AAA (Arrange-Act-Assert) pattern with explicit comment markers: **each marker appears at most once per test** (if you need two Acts or Asserts, write two tests): ```typescript @@ -203,7 +203,7 @@ Example (PushSingle): 2. Add a new case in `configureInfrastructureServices()` (`src/envilder/apps/shared/ContainerConfiguration.ts`) 3. No changes needed to application or domain layers -**Multi-Backend Support**: Already implemented — `configureInfrastructureServices()` selects +**Multi-Backend Support**: Already implemented: `configureInfrastructureServices()` selects provider based on `MapFileConfig.provider` (`aws` or `azure`). To add more providers, extend the provider selection logic in `ContainerConfiguration.ts`. @@ -220,31 +220,31 @@ but have **no code dependency** on the TypeScript core. (async `GetSecretAsync` + sync `GetSecret`), `MapFileConfig`, `EnvilderOptions`, `ParsedMapFile`, `SecretProviderType` enum - **Application** (`Application/`): - - `Env` — Static one-liner facade (`Load`, `ResolveFile`, `FromMapFile` + env-routing overloads) - - `EnvilderBuilder` — Fluent builder (`WithProvider`, `WithProfile`, `WithVaultUrl` → `Resolve`/`Inject`) - - `EnvilderClient` — Core resolver (resolves mappings, `InjectIntoEnvironment` static method) - - `MapFileParser` — Parses `$config` + variable mappings from JSON - - `SecretValidationExtensions` — Opt-in `ValidateSecrets()` extension + - `Env`: Static one-liner facade (`Load`, `ResolveFile`, `FromMapFile` + env-routing overloads) + - `EnvilderBuilder`: Fluent builder (`WithProvider`, `WithProfile`, `WithVaultUrl` → `Resolve`/`Inject`) + - `EnvilderClient`: Core resolver (resolves mappings, `InjectIntoEnvironment` static method) + - `MapFileParser`: Parses `$config` + variable mappings from JSON + - `SecretValidationExtensions`: Opt-in `ValidateSecrets()` extension (throws `SecretValidationException` for empty/missing values) - **Infrastructure** (`Infrastructure/`): - - `SecretProviderFactory` (internal) — Creates provider from + - `SecretProviderFactory` (internal): Creates provider from `MapFileConfig` + optional `EnvilderOptions` overrides. Validates cross-provider config (profile is AWS-only, vaultUrl is Azure-only) - - `Aws/AwsSsmSecretProvider` — `GetSecretAsync`: + - `Aws/AwsSsmSecretProvider`: `GetSecretAsync`: `GetParameterAsync(WithDecryption=true)`, catches `ParameterNotFoundException` → `null`. `GetSecret` (sync): wraps in `Task.Run()` to prevent `SynchronizationContext` deadlocks, 60s `CancellationTokenSource` timeout - - `Azure/AzureKeyVaultSecretProvider` — `GetSecretAsync`: + - `Azure/AzureKeyVaultSecretProvider`: `GetSecretAsync`: `SecretClient.GetSecretAsync()`, catches `RequestFailedException(404)` → `null`. `GetSecret` (sync): uses native `SecretClient.GetSecret()` (no deadlock risk) - - `Configuration/` — + - `Configuration/`: `EnvilderConfigurationBuilderExtensions.AddEnvilder(mapFilePath, options?)` integrates into `IConfigurationBuilder` pipeline; creates provider internally via factory - - `DependencyInjection/EnvilderServiceCollectionExtensions` — + - `DependencyInjection/EnvilderServiceCollectionExtensions`: `IServiceCollection.AddEnvilder(mapFilePath, options?)` for ASP.NET DI @@ -256,11 +256,11 @@ but have **no code dependency** on the TypeScript core. **Key patterns**: -- `SecretProviderFactory` is internal — consumers use the facade, builder, or `AddEnvilder()` extensions -- Pull-only — SDKs do not support push mode +- `SecretProviderFactory` is internal: consumers use the facade, builder, or `AddEnvilder()` extensions +- Pull-only: SDKs do not support push mode - `ISecretProvider.GetSecretAsync()` / `GetSecret()` return `null` for missing secrets (no exceptions) - `EnvilderClient.ResolveSecretsAsync()` / `ResolveSecrets()` silently omit missing secrets -- `SecretValidationExtensions.ValidateSecrets()` — opt-in post-resolution validation +- `SecretValidationExtensions.ValidateSecrets()`: opt-in post-resolution validation - Cross-provider validation: profile + Azure → error, vaultUrl + AWS → error **Tests** (`tests/sdks/dotnet/`): xUnit + NSubstitute + AwesomeAssertions. @@ -281,16 +281,16 @@ Naming: `Should__When_`. AAA pattern with comment markers. `EnvilderOptions`, `ParsedMapFile` dataclasses, `SecretProviderType` enum - **Application** (`application/`): - - `Envilder` (facade) — Primary entry point: `load(path)`, + - `Envilder` (facade): Primary entry point: `load(path)`, `resolve_file(path)`, `from_map_file(path)` fluent builder, plus env-routing overloads `load(env, mapping)` / `resolve_file(env, mapping)` - - `EnvilderClient` — Core resolver + - `EnvilderClient`: Core resolver (`resolve_secrets(map_file)` + `inject_into_environment(secrets)` static method sets `os.environ`) - - `MapFileParser` — Parses `$config` + variable mappings from JSON - - `secret_validation` — `validate_secrets(dict)` raises `SecretValidationError` for empty/missing values + - `MapFileParser`: Parses `$config` + variable mappings from JSON + - `secret_validation`: `validate_secrets(dict)` raises `SecretValidationError` for empty/missing values - **Infrastructure** (`infrastructure/`): `_SecretProviderFactory` (private by convention, not exported in `__all__`), `AwsSsmSecretProvider` (boto3), @@ -298,13 +298,13 @@ Naming: `Should__When_`. AAA pattern with comment markers. **Key patterns**: -- Synchronous API — uses `boto3` natively (no async/await) -- Protocol-based ports — Python `Protocol` instead of ABC -- `_SecretProviderFactory` is internal — consumers use the `Envilder` facade +- Synchronous API: uses `boto3` natively (no async/await) +- Protocol-based ports: Python `Protocol` instead of ABC +- `_SecretProviderFactory` is internal: consumers use the `Envilder` facade - `Envilder` facade is the primary public API (fluent: `from_map_file().with_provider().with_vault_url().inject()`) - `ISecretProvider.get_secret()` returns `None` for missing secrets (no exceptions) - `EnvilderClient.resolve_secrets()` silently omits missing secrets -- `validate_secrets()` — opt-in post-resolution validation +- `validate_secrets()`: opt-in post-resolution validation - Cross-provider validation: profile + Azure → error, vault_url + AWS → error **Tests** (`tests/sdks/python/`): pytest with `Should__When_` naming. @@ -328,29 +328,29 @@ AAA pattern with comment markers. `EnvilderOptions`, `ParsedMapFile` types, `SecretProviderType` enum - **Application** (`src/application/`): - - `Envilder` — Async facade (`load`, `resolveFile`, `fromMapFile` + env-routing overloads) - - `EnvilderClient` — Core resolver (`resolveSecrets`, `injectIntoEnvironment` static method sets `process.env`) - - `MapFileParser` — Parses `$config` + variable mappings from JSON - - `validateSecrets` — Opt-in validation throws `SecretValidationError` for empty/missing values + - `Envilder`: Async facade (`load`, `resolveFile`, `fromMapFile` + env-routing overloads) + - `EnvilderClient`: Core resolver (`resolveSecrets`, `injectIntoEnvironment` static method sets `process.env`) + - `MapFileParser`: Parses `$config` + variable mappings from JSON + - `validateSecrets`: Opt-in validation throws `SecretValidationError` for empty/missing values - **Infrastructure** (`src/infrastructure/`): - - `createSecretProvider` (not re-exported from barrel) — + - `createSecretProvider` (not re-exported from barrel): Creates provider from `MapFileConfig` + optional `EnvilderOptions` overrides - - `AwsSsmSecretProvider` — `GetParametersCommand` + - `AwsSsmSecretProvider`: `GetParametersCommand` (batch, up to 10 per request) with `WithDecryption: true`, missing parameters silently omitted via `InvalidParameters` - - `AzureKeyVaultSecretProvider` — `Promise.all` over `SecretClient.getSecret()` calls, catches 404 → omitted + - `AzureKeyVaultSecretProvider`: `Promise.all` over `SecretClient.getSecret()` calls, catches 404 → omitted **Key patterns**: -- Async-first — all provider and facade methods return `Promise` -- Interface-based ports — TypeScript `interface` for `ISecretProvider` -- `createSecretProvider` is not re-exported from the public barrel (`index.ts`) — consumers use the `Envilder` facade +- Async-first: all provider and facade methods return `Promise` +- Interface-based ports: TypeScript `interface` for `ISecretProvider` +- `createSecretProvider` is not re-exported from the public barrel (`index.ts`): consumers use the `Envilder` facade - `Envilder` facade is the primary public API (fluent: `fromMapFile().withProvider().withVaultUrl().inject()`) -- `ISecretProvider.getSecrets(names[])` returns `Map` — missing secrets silently omitted +- `ISecretProvider.getSecrets(names[])` returns `Map`: missing secrets silently omitted - `EnvilderClient.resolveSecrets()` delegates to `getSecrets()` in a single call -- `validateSecrets()` — opt-in post-resolution validation +- `validateSecrets()`: opt-in post-resolution validation - Cross-provider validation: profile + Azure → error, vaultUrl + AWS → error - `Map` used for mappings and resolved secrets diff --git a/.github/instructions/coding-and-testing-conventions.instructions.md b/.github/instructions/coding-and-testing-conventions.instructions.md index a9a16cae..3948d074 100644 --- a/.github/instructions/coding-and-testing-conventions.instructions.md +++ b/.github/instructions/coding-and-testing-conventions.instructions.md @@ -14,7 +14,7 @@ Apply these conventions as required defaults for source and test changes. - Inject `ILogger` instead of writing directly to console in domain or application code. - Never log raw secrets; use masked output patterns (for example `EnvironmentVariable.maskedValue`). - For tests, use Vitest naming: `Should__When_`. -- Structure tests with explicit AAA markers: `// Arrange`, `// Act`, `// Assert` — each at most once per test. +- Structure tests with explicit AAA markers: `// Arrange`, `// Act`, `// Assert`: each at most once per test. If you need two Acts or Asserts, write two tests. - Mock application-layer dependencies at port boundaries using `vi.fn()`. - For GitHub Action behavior changes, regenerate and verify the bundle with `pnpm build:gha` and `pnpm verify:gha`. diff --git a/.github/instructions/git-conventions.instructions.md b/.github/instructions/git-conventions.instructions.md index 58f7657d..4220a3b6 100644 --- a/.github/instructions/git-conventions.instructions.md +++ b/.github/instructions/git-conventions.instructions.md @@ -24,17 +24,17 @@ Apply these rules whenever making or validating git changes. ## GitHub CLI (`gh`) in PowerShell -- NEVER use inline `--body "..."` with multi-line content — PowerShell garbles encoding (hex escapes, collapsed newlines). -- NEVER use PowerShell here-strings (`@"..."@`) piped directly to `gh` — variable interpolation mangles backticks and special characters. +- NEVER use inline `--body "..."` with multi-line content: PowerShell garbles encoding (hex escapes, collapsed newlines). +- NEVER use PowerShell here-strings (`@"..."@`) piped directly to `gh`: variable interpolation mangles backticks and special characters. - Always use `--body-file` with a temp file for issue/PR bodies. -- Create the file via the editor (e.g., `create_file` tool) or `Set-Content` with `-Encoding utf8NoBOM` — never via `Out-File` with here-strings containing markdown backticks. +- Create the file via the editor (e.g., `create_file` tool) or `Set-Content` with `-Encoding utf8NoBOM`: never via `Out-File` with here-strings containing markdown backticks. ### Why encoding breaks PowerShell treats backticks (`` ` ``) as escape characters. In a here-string or double-quoted string: - `` `n `` becomes a literal newline -- `` `e `` becomes an ESC character (U+001B) — this corrupts words like `` `envilder `` into garbage +- `` `e `` becomes an ESC character (U+001B): this corrupts words like `` `envilder `` into garbage - `` `t `` becomes a tab This means any markdown with inline code (`` `envilder.json` ``) WILL be corrupted if passed through PowerShell string interpolation. diff --git a/.github/instructions/review-response.instructions.md b/.github/instructions/review-response.instructions.md index 64f18104..455e77e3 100644 --- a/.github/instructions/review-response.instructions.md +++ b/.github/instructions/review-response.instructions.md @@ -7,7 +7,7 @@ name: "PR Review Response Conventions" Apply these rules when drafting responses to PR comments. -**Every review comment MUST receive a reply on GitHub — no exceptions.** +**Every review comment MUST receive a reply on GitHub: no exceptions.** Whether addressed, skipped, or answered, always post a reply in the review thread. A comment without a GitHub reply is never considered done. diff --git a/.github/prompts/scaffold-feature.prompt.md b/.github/prompts/scaffold-feature.prompt.md index aa4b03cf..ac928031 100644 --- a/.github/prompts/scaffold-feature.prompt.md +++ b/.github/prompts/scaffold-feature.prompt.md @@ -81,7 +81,7 @@ After generating files, suggest: ## Constraints -- Follow hexagonal architecture — no infrastructure imports in domain or application +- Follow hexagonal architecture: no infrastructure imports in domain or application - Use InversifyJS decorators (`@injectable()`, `@inject()`) - One command + one handler per feature - Mirror `src/` structure under `tests/` for test files diff --git a/.github/skills/README.md b/.github/skills/README.md index 86a4714f..cb85498f 100644 --- a/.github/skills/README.md +++ b/.github/skills/README.md @@ -11,11 +11,11 @@ User ──→ Agent (persona + workflow) ──→ loads Skills (domain knowled ──→ delegates to Sub-agents ``` -- **Skills** live in `.github/skills/{name}/SKILL.md` — domain knowledge, +- **Skills** live in `.github/skills/{name}/SKILL.md`: domain knowledge, conventions, and procedures that agents load on demand. -- **Agents** live in `.github/agents/{name}.agent.md` — personas with specific +- **Agents** live in `.github/agents/{name}.agent.md`: personas with specific tools, workflows, and delegations. -- **Instructions** live in `.github/instructions/` — always-on rules scoped by +- **Instructions** live in `.github/instructions/`: always-on rules scoped by file pattern (architecture boundaries, coding conventions, git). ## Skills (24) @@ -33,7 +33,7 @@ User ──→ Agent (persona + workflow) ──→ loads Skills (domain knowled | Skill | Purpose | |-------|---------| -| `common-architecture-decisions` | ADR index — check before proposing changes | +| `common-architecture-decisions` | ADR index: check before proposing changes | | `common-git` | Conventional commits, branching, PR workflow | | `common-security` | Secret handling, Secretlint, OIDC, input validation | | `common-testing-conventions` | AAA pattern, naming, assertions across all stacks | @@ -81,7 +81,7 @@ User ──→ Agent (persona + workflow) ──→ loads Skills (domain knowled | Skill | Invocable | Purpose | |-------|-----------|---------| -| `grill-me` | ✅ | Stress-test a plan — interview relentlessly | +| `grill-me` | ✅ | Stress-test a plan: interview relentlessly | | `to-issues` | ✅ | Break plan into vertical-slice GitHub issues | | `zoom-out` | `/zoom-out` only | Map modules/callers at higher abstraction level | @@ -90,9 +90,9 @@ User ──→ Agent (persona + workflow) ──→ loads Skills (domain knowled | Agent | Role | Delegates to | |-------|------|-------------| | **TDD Coach** | Orchestrates Red-Green-Refactor. Plans, delegates, never writes code. | TDD Red, TDD Green, TDD Refactor | -| **TDD Red** | Writes one failing test | — | -| **TDD Green** | Writes minimum code to pass | — | -| **TDD Refactor** | Improves structure, keeps tests green | — | +| **TDD Red** | Writes one failing test | n/a | +| **TDD Green** | Writes minimum code to pass | n/a | +| **TDD Refactor** | Improves structure, keeps tests green | n/a | | **Code Reviewer** | 5-perspective analysis + verification | TDD Coach, PR Resolver | | **Content Designer** | Website, docs, changelogs, translations, CSS | Code Reviewer | | **PR Resolver** | Processes PR review comments, commits fixes, replies on GitHub | TDD Coach | @@ -133,17 +133,17 @@ user-invocable: true structural changes. 3. **Domain vocabulary**: Use terms from `CONTEXT.md` (map file, provider, facade, port, adapter, etc.). -4. **`common-*` skills are auto-loaded** (`user-invocable: false`) — they apply +4. **`common-*` skills are auto-loaded** (`user-invocable: false`): they apply silently when relevant via instruction file `applyTo` patterns. 5. **`disable-model-invocation: true`** means the skill is only triggered by the - user typing `/skill-name` — the model won't auto-load it. + user typing `/skill-name`: the model won't auto-load it. ## Influences -- [Matt Pocock's skills](https://github.com/mattpocock/skills) — Patterns adopted: +- [Matt Pocock's skills](https://github.com/mattpocock/skills): Patterns adopted: `grill-me`, `to-issues`, `zoom-out`, "build a feedback loop first" philosophy in bug investigation, deep modules heuristic in TDD planning, and the `CONTEXT.md` domain glossary convention. -- [VS Code Copilot docs — Nested subagents](https://code.visualstudio.com/docs/copilot/agents/subagents#_nested-subagents) — +- [VS Code Copilot docs: Nested subagents](https://code.visualstudio.com/docs/copilot/agents/subagents#_nested-subagents): Inspiration for the TDD Coach multi-agent architecture (coordinator + specialized workers). diff --git a/.github/skills/code-bug-investigation/SKILL.md b/.github/skills/code-bug-investigation/SKILL.md index 902183b6..7dbb293a 100644 --- a/.github/skills/code-bug-investigation/SKILL.md +++ b/.github/skills/code-bug-investigation/SKILL.md @@ -17,7 +17,7 @@ Structured workflow for going from bug report to reproduction-ready TDD plan. - A user reports unexpected output or error - A test failure indicates a regression -## Phase 1 — Build a Feedback Loop +## Phase 1: Build a Feedback Loop **This is the skill.** Everything else is mechanical. Before investigating anything, establish a tight loop that lets you observe the bug: @@ -32,7 +32,7 @@ anything, establish a tight loop that lets you observe the bug: If you can't reproduce → stop and report to the user immediately. No guessing. -## Phase 2 — Gather Issue Details +## Phase 2: Gather Issue Details **From GitHub issue:** @@ -46,14 +46,14 @@ Extract: title, description, steps to reproduce, expected vs actual behavior. Summarize: what's happening, what should happen, reproduction conditions. -## Phase 3 — Investigate and Locate +## Phase 3: Investigate and Locate -1. Identify the domain area — which handler, service, or component -2. Read the affected code — understand current behavior -3. Check existing tests — why didn't they catch this? -4. Identify root cause — pinpoint the exact code path +1. Identify the domain area: which handler, service, or component +2. Read the affected code: understand current behavior +3. Check existing tests: why didn't they catch this? +4. Identify root cause: pinpoint the exact code path -## Phase 4 — Present Analysis +## Phase 4: Present Analysis Before writing any code, present findings: @@ -62,7 +62,7 @@ Before writing any code, present findings: **Issue:** {title or summary} **Root cause:** {explanation} -**Affected code:** {file}:{line range} — {what's wrong} +**Affected code:** {file}:{line range}: {what's wrong} **Existing coverage:** {tests that exist but missed the bug} **Reproduction plan:** @@ -76,14 +76,14 @@ Proceed with reproduction test? (Y/n) Wait for user confirmation before proceeding to TDD cycle. -## Phase 5 — Handoff to TDD +## Phase 5: Handoff to TDD After analysis is confirmed: -1. **RED** — Write a failing test that reproduces the bug (asserts correct +1. **RED**: Write a failing test that reproduces the bug (asserts correct behavior, fails because bug exists) -2. **GREEN** — Fix the production code minimally -3. **REFACTOR** — Clean up if needed +2. **GREEN**: Fix the production code minimally +3. **REFACTOR**: Clean up if needed ## Investigation Tools @@ -94,10 +94,10 @@ After analysis is confirmed: ## Rules -- **Never fix without reproducing first** — a failing test is mandatory -- **One bug per cycle** — multiple bugs need separate investigations -- **Present analysis before acting** — user validates understanding first -- **Report blockers immediately** — if reproduction fails, stop and explain +- **Never fix without reproducing first**: a failing test is mandatory +- **One bug per cycle**: multiple bugs need separate investigations +- **Present analysis before acting**: user validates understanding first +- **Report blockers immediately**: if reproduction fails, stop and explain ## Summary Format @@ -108,8 +108,8 @@ After fix is complete: **Issue:** {title} **Root cause:** {one-line explanation} -**Red:** {test_file}::{test_name} — reproduced ✓ -**Green:** {production_file} — {what was fixed} +**Red:** {test_file}::{test_name}: reproduced ✓ +**Green:** {production_file}: {what was fixed} **Refactor:** {what improved, or "no changes needed"} -**Tests:** pnpm test — {N} passed, 0 failed +**Tests:** pnpm test: {N} passed, 0 failed ``` diff --git a/.github/skills/code-quality-crap/SKILL.md b/.github/skills/code-quality-crap/SKILL.md index 9e5784ea..f074de97 100644 --- a/.github/skills/code-quality-crap/SKILL.md +++ b/.github/skills/code-quality-crap/SKILL.md @@ -6,7 +6,7 @@ description: >- or determining minimum test coverage requirements. --- -# Code Quality — CRAP Score +# Code Quality: CRAP Score CRAP (Change Risk Anti-Patterns) measures the risk of a method based on cyclomatic complexity and test coverage. @@ -43,7 +43,7 @@ providing a safety margin: | 3 | 40%+ | | 4 | 60%+ | | 5 | 80%+ | -| 6+ | **Not achievable** — must split to reduce complexity | +| 6+ | **Not achievable**: must split to reduce complexity | ## Actions by Scenario @@ -51,7 +51,7 @@ providing a safety margin: |----------|--------| | CRAP >= 6 due to high complexity | Extract complex branches into smaller methods | | CRAP >= 6 due to low coverage | Add tests (new Red/Green cycle) | -| Complexity 6+ regardless of coverage | Must split — CRAP floor equals complexity | +| Complexity 6+ regardless of coverage | Must split: CRAP floor equals complexity | ## Severity Classification diff --git a/.github/skills/code-refactoring/SKILL.md b/.github/skills/code-refactoring/SKILL.md index 15fff136..fca50e4f 100644 --- a/.github/skills/code-refactoring/SKILL.md +++ b/.github/skills/code-refactoring/SKILL.md @@ -73,16 +73,16 @@ For each approved refactoring: **Formatter:** ran ✓ ### Changes -1. {file} — {what changed} +1. {file}: {what changed} ``` ## Constraints -- **Never change observable behavior** — refactoring preserves outputs +- **Never change observable behavior**: refactoring preserves outputs - Respect hexagonal architecture boundaries - Preserve existing DI wiring patterns (InversifyJS) - If a refactoring breaks a test, **revert it** and report -- One change per step — never batch multiple refactorings without testing +- One change per step: never batch multiple refactorings without testing ## SOLID Reference diff --git a/.github/skills/code-review-perspectives/SKILL.md b/.github/skills/code-review-perspectives/SKILL.md index fa28df93..0dc42537 100644 --- a/.github/skills/code-review-perspectives/SKILL.md +++ b/.github/skills/code-review-perspectives/SKILL.md @@ -45,7 +45,7 @@ Run independently, then synthesize into a deduplicated prioritised report. - Biome style (single quotes, semicolons, 2-space indent, trailing commas) - Test naming: `Should__When_` -- AAA markers: `// Arrange`, `// Act`, `// Assert` — each at most once per test +- AAA markers: `// Arrange`, `// Act`, `// Assert`: each at most once per test - InversifyJS decorator usage: `@injectable()`, `@inject(TYPES.X)` - Conventional commits in PR title @@ -54,7 +54,7 @@ Run independently, then synthesize into a deduplicated prioritised report. See `code-quality-crap` skill for formula and thresholds. - Flag methods with cyclomatic complexity ≥ 4 lacking proportional coverage -- Flag methods with complexity ≥ 6 — recommend extraction +- Flag methods with complexity ≥ 6: recommend extraction ## Severity Model @@ -78,7 +78,7 @@ See `code-quality-crap` skill for formula and thresholds. ```text ## Findings -### [Critical/High/Medium/Low] — {title} +### [Critical/High/Medium/Low]: {title} **File:** {path}:{line} **Why:** {explanation} **Fix:** {direction} @@ -87,16 +87,16 @@ See `code-quality-crap` skill for formula and thresholds. - {assumptions or clarifications needed} ## Summary -{1-2 sentence overview — AFTER findings, not before} +{1-2 sentence overview: AFTER findings, not before} ``` ## Verification After analysis, verify findings before reporting: -1. `pnpm test` — confirm test suite passes -2. `biome check && tsc --noEmit` — lint compliance (no modifications) -3. `pnpm format:check` — formatting (no modifications) +1. `pnpm test`: confirm test suite passes +2. `biome check && tsc --noEmit`: lint compliance (no modifications) +3. `pnpm format:check`: formatting (no modifications) 4. Browser checks for website/UI changes (Playwright) 5. Stack-specific: `dotnet build`/`dotnet test`, `make check-sdk-python` @@ -106,4 +106,4 @@ Only report **confirmed** findings. Downgrade unverified suspicions. - Do not report style-only nits unless they block quality gates - State assumptions explicitly -- Never modify files during review — read-only analysis only +- Never modify files during review: read-only analysis only diff --git a/.github/skills/common-architecture-decisions/SKILL.md b/.github/skills/common-architecture-decisions/SKILL.md index 3a07bb91..a40df6ad 100644 --- a/.github/skills/common-architecture-decisions/SKILL.md +++ b/.github/skills/common-architecture-decisions/SKILL.md @@ -21,7 +21,7 @@ behind tooling choices and architectural patterns before proposing changes. - When reviewing code that seems inconsistent with project conventions - When adding a new SDK and need to follow established patterns - When onboarding and need to understand "why" behind technical choices -- Before writing tests — check ADR-0002 for the correct tooling per stack +- Before writing tests: check ADR-0002 for the correct tooling per stack ## ADR Index @@ -87,4 +87,4 @@ What we chose and the details. ## When to Reconsider ``` -Number sequentially. Keep scope focused — one decision per ADR. +Number sequentially. Keep scope focused: one decision per ADR. diff --git a/.github/skills/common-git/reference.md b/.github/skills/common-git/reference.md index 3fb45a6f..f2a864ff 100644 --- a/.github/skills/common-git/reference.md +++ b/.github/skills/common-git/reference.md @@ -1,4 +1,4 @@ -# Git — Quick Reference +# Git: Quick Reference ## Commit Types diff --git a/.github/skills/common-security/SKILL.md b/.github/skills/common-security/SKILL.md index e3022171..bc59d018 100644 --- a/.github/skills/common-security/SKILL.md +++ b/.github/skills/common-security/SKILL.md @@ -27,9 +27,9 @@ multi-runtime SDK platform that manages secrets from AWS SSM and Azure Key Vault ### Never Expose Secrets in Output - **CLI/GHA**: Use `EnvironmentVariable.maskedValue` (shows last 3 chars) for logging -- **SDKs**: Never log resolved secret values — log only the key name +- **SDKs**: Never log resolved secret values: log only the key name - **Tests**: Use `envilder.json` to resolve test tokens; never hardcode tokens -- **Website**: No secrets — it's a static site +- **Website**: No secrets: it's a static site ### Storage Rules @@ -53,11 +53,11 @@ the commit is blocked. - **Always** use `aws-actions/configure-aws-credentials` with `role-to-assume` - **Never** store `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` as GitHub Secrets -- OIDC tokens are short-lived and scoped — no rotation needed +- OIDC tokens are short-lived and scoped: no rotation needed ### GitHub Action Inputs -- GHA reads inputs from `process.env.INPUT_*` — validate before use +- GHA reads inputs from `process.env.INPUT_*`: validate before use - The `map` input (file path) must be validated to prevent path traversal - Never interpolate GHA inputs directly into shell commands @@ -71,12 +71,12 @@ the commit is blocked. ### CLI -- Commander validates option types — but validate semantic constraints: +- Commander validates option types: but validate semantic constraints: - `--map` path must exist and be a `.json` file - `--provider` must be one of `aws` | `azure` (case-insensitive) - `--vault-url` must be a valid HTTPS URL matching `*.vault.azure.net` - Never pass CLI arguments to shell commands unsanitized -- Use custom domain errors (`InvalidArgumentError`) — not generic exceptions +- Use custom domain errors (`InvalidArgumentError`): not generic exceptions ### SDKs @@ -87,7 +87,7 @@ the commit is blocked. ### Website -- Static site (Astro) — no user input at runtime +- Static site (Astro): no user input at runtime - Build-time i18n: translation keys are developer-controlled, not user-supplied ## 4. Supply Chain Security @@ -102,16 +102,16 @@ the commit is blocked. ### Rules -- Lock files **must** be committed — never `.gitignore` them +- Lock files **must** be committed: never `.gitignore` them - Dependabot (or Renovate) configured for automatic dependency updates - Review advisories on every dependency update PR -- `@vercel/ncc` bundles GHA — verify bundle is up-to-date (`pnpm verify:gha`) +- `@vercel/ncc` bundles GHA: verify bundle is up-to-date (`pnpm verify:gha`) - Pin GitHub Actions to full commit SHA (not `@v4` tags) in production workflows ### CDK -- Keep `aws-cdk-lib` up to date — security patches affect deployed infra -- CDK synth output (`cdk.out/`) is `.gitignored` — never commit CloudFormation templates +- Keep `aws-cdk-lib` up to date: security patches affect deployed infra +- CDK synth output (`cdk.out/`) is `.gitignored`: never commit CloudFormation templates ## 5. SDK-Specific Security @@ -120,34 +120,34 @@ the commit is blocked. - Always use `WithDecryption: true` for SecureString parameters - Never log the decrypted parameter value - Credential chain: SDK default chain (env vars → profile → instance role) -- If `profile` is specified, only use `CredentialProfileStoreChain` — don't mix +- If `profile` is specified, only use `CredentialProfileStoreChain`: don't mix ### Azure Key Vault Provider -- Use `DefaultAzureCredential` — never hardcode `clientId`/`clientSecret` +- Use `DefaultAzureCredential`: never hardcode `clientId`/`clientSecret` - Vault URL validation: must match `https://*.vault.azure.net` - TLS certificate validation: enabled in production, only disabled in tests against Lowkey Vault (emulator) ### Cross-Provider -- `EnvilderOptions` overrides `$config` — validate that overrides don't +- `EnvilderOptions` overrides `$config`: validate that overrides don't introduce insecure combinations (e.g., disabling encryption) - Missing secrets → `null`/`None` (silent). Validation is opt-in via - `validateSecrets()` — document this to users clearly + `validateSecrets()`: document this to users clearly ## 6. Website Security -- Astro generates static HTML — no server-side injection possible +- Astro generates static HTML: no server-side injection possible - External links: use `rel="noopener noreferrer"` on `target="_blank"` links - No inline scripts or `dangerouslySetInnerHTML` equivalents - CSP headers configured at CDN/CloudFront level (via CDK) ## 7. Testing Security -- Acceptance tests use emulators (LocalStack, Lowkey Vault) — never real +- Acceptance tests use emulators (LocalStack, Lowkey Vault): never real cloud endpoints -- `LOCALSTACK_AUTH_TOKEN` resolved via Envilder itself (dogfooding) — stored +- `LOCALSTACK_AUTH_TOKEN` resolved via Envilder itself (dogfooding): stored in SSM, never in code - Test cleanup: containers destroyed after test run (TestContainers lifecycle) - TLS disabled only for Lowkey Vault container tests (self-signed cert) diff --git a/.github/skills/common-testing-conventions/SKILL.md b/.github/skills/common-testing-conventions/SKILL.md index c5148c8d..777601ac 100644 --- a/.github/skills/common-testing-conventions/SKILL.md +++ b/.github/skills/common-testing-conventions/SKILL.md @@ -33,7 +33,7 @@ Exception: `// Arrange`, `// Act`, `// Assert` comments are REQUIRED in tests. | File | Description | | ---- | ----------- | | [dotnet.md](./dotnet.md) | .NET testing stack (xUnit, AwesomeAssertions, NSubstitute, Bogus, Verify.Xunit, WireMock, Testcontainers) | -| [typescript.md](./typescript.md) | TypeScript testing stack — CLI, SDK, CDK, Website (Vitest, Playwright, Biome) | +| [typescript.md](./typescript.md) | TypeScript testing stack: CLI, SDK, CDK, Website (Vitest, Playwright, Biome) | | [python.md](./python.md) | Python testing stack (pytest, Mock/AsyncMock, pytest-snapshot, black, mypy, Pydantic) | | [examples.md](./examples.md) | Full test examples for C# and TypeScript | | [reference.md](./reference.md) | Naming rules, anti-patterns, checklist | @@ -64,20 +64,20 @@ public async Task Should_CreateGroup_When_RequestIsValid() **Rules:** -- **Each comment (`// Arrange`, `// Act`, `// Assert`) appears AT MOST ONCE per test** — if you need two actions, +- **Each comment (`// Arrange`, `// Act`, `// Assert`) appears AT MOST ONCE per test**: if you need two actions, write two tests - **Act = one single invocation on the SUT.** Multiple statements in Act only if they are genuinely part of the same logical action (rare and exceptional). Two independent operations = two tests. -- **AAA markers are mandatory in ALL tests** — including structural guards, +- **AAA markers are mandatory in ALL tests**: including structural guards, static completeness checks, and data validation tests. No exceptions. - Each section clearly separated by comments - Never mix phases - **All assertions belong in Assert only.** No `expect()`, `.Should()`, `assert`, or any verification statement in Arrange or Act. If you feel tempted to assert in Arrange (precondition check), extract - it to a separate test or use a guard clause that throws — not an assertion. + it to a separate test or use a guard clause that throws: not an assertion. - **No `if`, `switch`, or conditional logic** inside Arrange, Act, or Assert blocks -- **No `try/catch/finally`** inside tests — use framework teardown (`IAsyncLifetime`, `[ClassCleanup]`, pytest `yield` fixtures) -- **No `// Act & Assert` combined blocks** — Act and Assert are ALWAYS separate phases +- **No `try/catch/finally`** inside tests: use framework teardown (`IAsyncLifetime`, `[ClassCleanup]`, pytest `yield` fixtures) +- **No `// Act & Assert` combined blocks**: Act and Assert are ALWAYS separate phases - For exceptions: C# → `AwesomeAssertions` `.Should().ThrowAsync()` | Python → `lambda` + `pytest.raises()` | Vitest → `expect(...).rejects.toThrow()` - Omit comment if section is empty @@ -137,12 +137,12 @@ public class CreateGroupCommandHandlerTests See the dedicated supporting file for each stack: -- **.NET Backend:** [dotnet.md](./dotnet.md) — xUnit, AwesomeAssertions, NSubstitute, +- **.NET Backend:** [dotnet.md](./dotnet.md): xUnit, AwesomeAssertions, NSubstitute, AutoFixture, Bogus, Verify.Xunit, WireMock.Net, Testcontainers (PostgreSQL, LocalStack) -- **TypeScript (CLI, SDK, CDK, Website):** [typescript.md](./typescript.md) — Vitest +- **TypeScript (CLI, SDK, CDK, Website):** [typescript.md](./typescript.md): Vitest (CLI/SDK/CDK/Website), Playwright, Biome -- **Python:** [python.md](./python.md) — pytest, pytest-asyncio, pytest-snapshot, +- **Python:** [python.md](./python.md): pytest, pytest-asyncio, pytest-snapshot, unittest.mock, black, mypy, Pydantic ## Related Skills diff --git a/.github/skills/common-testing-conventions/dotnet.md b/.github/skills/common-testing-conventions/dotnet.md index eb7d5b97..176cb43b 100644 --- a/.github/skills/common-testing-conventions/dotnet.md +++ b/.github/skills/common-testing-conventions/dotnet.md @@ -120,7 +120,7 @@ public class ApiServicesFactory : LocalStackWebBaseServicesFactory Generator[None, None, None]: original = {k: os.environ.get(k) for k in ENV_VARS} @@ -245,7 +245,7 @@ def Should_ResolveSecret_When_EnvConfigured(aws_env: None) -> None: # Assert assert actual["DB_URL"] == expected -# BAD — try/finally in test body +# BAD: try/finally in test body def Should_ResolveSecret_When_EnvConfigured() -> None: original = os.environ.get("AWS_ENDPOINT_URL") try: diff --git a/.github/skills/common-testing-conventions/reference.md b/.github/skills/common-testing-conventions/reference.md index 25bb74d0..59591cd6 100644 --- a/.github/skills/common-testing-conventions/reference.md +++ b/.github/skills/common-testing-conventions/reference.md @@ -230,7 +230,7 @@ it("Should_CallHandleChange_When_MaxInputChanges", async () => { ```typescript // BAD - Two independent operations in Act it('Should_HaveIdenticalKeys_When_ComparedToEnglish', () => { - // Arrange — keys computed above + // Arrange: keys computed above // Act const missing = enKeys.filter((k) => !caKeys.includes(k)); @@ -243,7 +243,7 @@ it('Should_HaveIdenticalKeys_When_ComparedToEnglish', () => { // GOOD - Split into two tests (one action each) it('Should_HaveNoMissingKeys_When_CatalanComparedToEnglish', () => { - // Arrange — keys computed above + // Arrange: keys computed above // Act const missing = enKeys.filter((k) => !caKeys.includes(k)); @@ -253,7 +253,7 @@ it('Should_HaveNoMissingKeys_When_CatalanComparedToEnglish', () => { }); it('Should_HaveNoExtraKeys_When_CatalanComparedToEnglish', () => { - // Arrange — keys computed above + // Arrange: keys computed above // Act const extra = caKeys.filter((k) => !enKeys.includes(k)); @@ -268,9 +268,9 @@ it('Should_HaveNoExtraKeys_When_CatalanComparedToEnglish', () => { ```typescript // BAD - No production code exercised, AAA markers are meaningless it('Should_HaveIdenticalKeys_When_ComparedToEnglish', () => { - // Arrange — enKeys and caKeys computed in describe scope + // Arrange: enKeys and caKeys computed in describe scope - // Act — comparison done in arrange ← admits there is no Act + // Act: comparison done in arrange ← admits there is no Act // Assert expect(missingInCa).toEqual([]); @@ -367,5 +367,5 @@ it('Should_TransformData_When_InputIsValid', () => { 7. ✓ Tests are independent and isolated 8. ✓ No shared mutable state between tests 9. ✓ **No `if`, `switch`, `try/catch`** inside Arrange, Act, or Assert blocks -10. ✓ One scenario per test — if branching is needed, create separate tests -11. ✓ **Each `// Arrange`, `// Act`, `// Assert` comment appears at most once per test** — no duplicate blocks +10. ✓ One scenario per test: if branching is needed, create separate tests +11. ✓ **Each `// Arrange`, `// Act`, `// Assert` comment appears at most once per test**: no duplicate blocks diff --git a/.github/skills/common-testing-conventions/typescript.md b/.github/skills/common-testing-conventions/typescript.md index 21af36b3..78f6ac13 100644 --- a/.github/skills/common-testing-conventions/typescript.md +++ b/.github/skills/common-testing-conventions/typescript.md @@ -205,10 +205,10 @@ Root `biome.json` enforces: ## TypeScript Strict Rules - Use `import type` for type-only imports. -- TypeScript strict mode is enabled — respect all strict checks. +- TypeScript strict mode is enabled: respect all strict checks. - Always run `pnpm format` after modifying TypeScript files. -## Test Cleanup — No `try/catch/finally` in Tests +## Test Cleanup: No `try/catch/finally` in Tests **NEVER** use `try/catch`, `try/finally`, `if`, or any control flow inside test functions. Use framework teardown mechanisms instead: @@ -220,7 +220,7 @@ Use framework teardown mechanisms instead: | Vitest spy cleanup | `vi.restoreAllMocks()` in `afterEach` | ```typescript -// GOOD — cleanup via afterEach +// GOOD: cleanup via afterEach describe('resolve', () => { const originalEnv = process.env; @@ -241,7 +241,7 @@ describe('resolve', () => { }); }); -// BAD — try/finally in test body +// BAD: try/finally in test body it('Should_ResolveSecret_When_EnvConfigured', async () => { const original = process.env.AWS_ENDPOINT_URL; try { diff --git a/.github/skills/core-testing/SKILL.md b/.github/skills/core-testing/SKILL.md index d543fe89..cd7534b4 100644 --- a/.github/skills/core-testing/SKILL.md +++ b/.github/skills/core-testing/SKILL.md @@ -81,12 +81,12 @@ confidence level across unit, integration, and e2e coverage. ## Quick Prompt Examples - "Use testing-conventions for `PullSecretsToEnvCommandHandler` and add missing error-path tests." -- "Apply testing-conventions to review `tests/envilder/apps/gha/Gha.test.ts` for naming and AAA compliance." +- "Apply testing-conventions to review `tests/envilder/apps/gha/entry/Gha.test.ts` for naming and AAA compliance." - "Use testing-conventions to design e2e coverage for SSM not-found behavior." ## Anti-Pattern: Duplicate Act/Assert Blocks -**Wrong** — two Acts and Asserts in one test: +**Wrong**: two Acts and Asserts in one test: ```typescript it('Should_HandleParameters_When_Called', async () => { @@ -107,7 +107,7 @@ it('Should_HandleParameters_When_Called', async () => { }); ``` -**Correct** — split into two focused tests: +**Correct**: split into two focused tests: ```typescript it('Should_SaveEnvironment_When_CommandAProvided', async () => { diff --git a/.github/skills/doc-maintenance/SKILL.md b/.github/skills/doc-maintenance/SKILL.md index 96236be5..4a955188 100644 --- a/.github/skills/doc-maintenance/SKILL.md +++ b/.github/skills/doc-maintenance/SKILL.md @@ -58,7 +58,7 @@ Use these categories matching existing style: - Group under the current release section or create a new one when requested ```markdown -## [1.2.0] — 2026-05-01 +## [1.2.0]: 2026-05-01 ### Added @@ -76,16 +76,16 @@ Use these categories matching existing style: 3. **Update** the smallest set of sections needed for correctness 4. **Cross-check** consistency across related docs (use `doc-sync` skill for comprehensive audit) -5. **Validate** — run `pnpm lint` to check formatting and consistency -6. **Summarize** — list updated files and what was synchronized +5. **Validate**: run `pnpm lint` to check formatting and consistency +6. **Summarize**: list updated files and what was synchronized ## Constraints -- **Never invent features** — document only what exists in code +- **Never invent features**: document only what exists in code - **Verify claims** against current source files before writing - **Preserve existing structure** and tone unless explicitly asked to refactor -- **Prefer documentation-only edits** — don't modify source unless asked -- **Keep examples minimal and runnable** — avoid hypothetical code +- **Prefer documentation-only edits**: don't modify source unless asked +- **Keep examples minimal and runnable**: avoid hypothetical code - **Don't modify ROADMAP.md** without explicit request (it's strategic) ## Validation diff --git a/.github/skills/doc-sync/SKILL.md b/.github/skills/doc-sync/SKILL.md index 360df888..5e0b8acd 100644 --- a/.github/skills/doc-sync/SKILL.md +++ b/.github/skills/doc-sync/SKILL.md @@ -4,7 +4,7 @@ description: 'Audit and synchronize documentation across website, READMEs, and d argument-hint: 'feature area to audit or "full" for complete audit' --- -# Doc Sync — Cross-Surface Documentation Alignment +# Doc Sync: Cross-Surface Documentation Alignment Audit and synchronize documentation across all surfaces to prevent drift. @@ -48,7 +48,7 @@ For each feature area, identify the authoritative source: | Area | Source of Truth | |------|-----------------| -| CLI flags/options | `src/envilder/apps/cli/Cli.ts` | +| CLI flags/options | `src/envilder/apps/cli/entry/Cli.ts` | | GHA inputs | `github-action/action.yml` | | SDK public API | SDK source code (`src/sdks/{runtime}/`) | | Providers | `src/envilder/core/infrastructure/` | @@ -58,14 +58,14 @@ For each feature area, identify the authoritative source: For each documentation surface, check: -- [ ] **Code examples compile/run** — verify syntax matches current API -- [ ] **CLI flags match** — documented flags exist in `Cli.ts` -- [ ] **GHA inputs match** — documented inputs exist in `action.yml` -- [ ] **SDK methods match** — documented methods exist in source -- [ ] **Install commands correct** — package names, versions, registries -- [ ] **Provider names consistent** — `aws`/`azure` naming across all docs -- [ ] **Links not broken** — internal cross-references resolve -- [ ] **i18n complete** — all 3 locales (en, ca, es) have matching keys +- [ ] **Code examples compile/run**: verify syntax matches current API +- [ ] **CLI flags match**: documented flags exist in `Cli.ts` +- [ ] **GHA inputs match**: documented inputs exist in `action.yml` +- [ ] **SDK methods match**: documented methods exist in source +- [ ] **Install commands correct**: package names, versions, registries +- [ ] **Provider names consistent**: `aws`/`azure` naming across all docs +- [ ] **Links not broken**: internal cross-references resolve +- [ ] **i18n complete**: all 3 locales (en, ca, es) have matching keys ### 4. Report Drift @@ -82,8 +82,8 @@ Present findings in a structured table: ## Alignment Actions -1. {file} — {what to update} -2. {file} — {what to update} +1. {file}: {what to update} +2. {file}: {what to update} ``` ### 5. Apply Fixes diff --git a/.github/skills/dotnet-testing/SKILL.md b/.github/skills/dotnet-testing/SKILL.md index 6b2c8085..368d5f22 100644 --- a/.github/skills/dotnet-testing/SKILL.md +++ b/.github/skills/dotnet-testing/SKILL.md @@ -15,7 +15,7 @@ These are **rules**, not guidelines. ### NO Comments Except AAA Markers * **NEVER write XML summaries** on test methods or test classes -* **NEVER write explanatory comments** — code must be self-explanatory +* **NEVER write explanatory comments**: code must be self-explanatory * **Only `// Arrange`, `// Act`, `// Assert`** comments are allowed in tests * The test name `Should_X_When_Y` already documents the intent @@ -47,19 +47,19 @@ These are **rules**, not guidelines. * Each phase **MUST** be separated with comments * **Never mix phases** * **Each comment (`// Arrange`, `// Act`, `// Assert`) appears AT MOST ONCE - per test** — if you need two actions or two asserts, write two tests + per test**: if you need two actions or two asserts, write two tests * **Act = one single invocation on the SUT.** Multiple statements in Act only if they are genuinely part of the same logical action (rare and exceptional). Two independent operations = two tests. * **All assertions belong in Assert only.** No `.Should()` in Arrange or Act. If you need a precondition check, extract it to a separate test or use a - guard clause that throws — not an assertion. -* **AAA markers are mandatory in ALL tests** — including structural guards, + guard clause that throws: not an assertion. +* **AAA markers are mandatory in ALL tests**: including structural guards, static completeness checks, and data validation tests. No exceptions. * **No `if`, `switch`, or conditional logic** inside Arrange, Act, or Assert -* **No `try/catch/finally`** inside tests — use `IAsyncLifetime` or +* **No `try/catch/finally`** inside tests: use `IAsyncLifetime` or `IDisposable` for teardown -* **No `// Act & Assert` combined blocks** — Act and Assert are ALWAYS separate +* **No `// Act & Assert` combined blocks**: Act and Assert are ALWAYS separate * For exceptions: `act.Should().ThrowAsync()` (AwesomeAssertions) * Omit comment if section is empty * If a test needs branching, split it into separate tests @@ -98,7 +98,7 @@ Should_{ExpectedBehavior}_When_{Condition} * **NO** natural language * **NO** vague names (`Should_Work`, `TestHandler`) * **NO** missing `When` clause -* Method names only — xUnit uses `[Fact]` or `[Theory]`, not description strings +* Method names only: xUnit uses `[Fact]` or `[Theory]`, not description strings --- diff --git a/.github/skills/grill-me/ADR-FORMAT.md b/.github/skills/grill-me/ADR-FORMAT.md index 5ff6b776..00b5f43f 100644 --- a/.github/skills/grill-me/ADR-FORMAT.md +++ b/.github/skills/grill-me/ADR-FORMAT.md @@ -3,7 +3,7 @@ ADRs live in `docs/adr/` and use sequential numbering: `0001-slug.md`, `0002-slug.md`, etc. -Create the `docs/adr/` directory lazily — only when the first ADR is needed. +Create the `docs/adr/` directory lazily: only when the first ADR is needed. ## Template @@ -14,17 +14,17 @@ Create the `docs/adr/` directory lazily — only when the first ADR is needed. ``` That's it. An ADR can be a single paragraph. The value is in recording *that* a -decision was made and *why* — not in filling out sections. +decision was made and *why*: not in filling out sections. ## Optional Sections Only include these when they add genuine value. Most ADRs won't need them. - **Status** frontmatter (`proposed | accepted | deprecated | superseded by - ADR-NNNN`) — useful when decisions are revisited -- **Considered Options** — only when the rejected alternatives are worth + ADR-NNNN`): useful when decisions are revisited +- **Considered Options**: only when the rejected alternatives are worth remembering -- **Consequences** — only when non-obvious downstream effects need to be called +- **Consequences**: only when non-obvious downstream effects need to be called out ## Numbering @@ -35,13 +35,13 @@ Scan `docs/adr/` for the highest existing number and increment by one. All three of these must be true: -1. **Hard to reverse** — the cost of changing your mind later is meaningful -2. **Surprising without context** — a future reader will look at the code and +1. **Hard to reverse**: the cost of changing your mind later is meaningful +2. **Surprising without context**: a future reader will look at the code and wonder "why on earth did they do it this way?" -3. **The result of a real trade-off** — there were genuine alternatives and you +3. **The result of a real trade-off**: there were genuine alternatives and you picked one for specific reasons -If a decision is easy to reverse, skip it — you'll just reverse it. If it's not +If a decision is easy to reverse, skip it: you'll just reverse it. If it's not surprising, nobody will wonder why. If there was no real alternative, there's nothing to record beyond "we did the obvious thing." @@ -52,7 +52,7 @@ nothing to record beyond "we did the obvious thing." - **Integration patterns between contexts.** "Ordering and Billing communicate via domain events, not synchronous HTTP." - **Technology choices that carry lock-in.** Database, message bus, auth - provider, deployment target. Not every library — just the ones that would take + provider, deployment target. Not every library: just the ones that would take a quarter to swap out. - **Boundary and scope decisions.** "Customer data is owned by the Customer context; other contexts reference it by ID only." The explicit no-s are as @@ -65,5 +65,5 @@ nothing to record beyond "we did the obvious thing." compliance requirements." "Response times must be under 200ms because of the partner API contract." - **Rejected alternatives when the rejection is non-obvious.** If you considered - GraphQL and picked REST for subtle reasons, record it — otherwise someone will + GraphQL and picked REST for subtle reasons, record it: otherwise someone will suggest GraphQL again in six months. diff --git a/.github/skills/grill-me/CONTEXT-FORMAT.md b/.github/skills/grill-me/CONTEXT-FORMAT.md index 99242208..f6e457d6 100644 --- a/.github/skills/grill-me/CONTEXT-FORMAT.md +++ b/.github/skills/grill-me/CONTEXT-FORMAT.md @@ -42,9 +42,9 @@ where they live, and how they relate to each other: ## Contexts -- [Ordering](./src/ordering/CONTEXT.md) — receives and tracks customer orders -- [Billing](./src/billing/CONTEXT.md) — generates invoices and processes payments -- [Fulfillment](./src/fulfillment/CONTEXT.md) — manages warehouse picking and shipping +- [Ordering](./src/ordering/CONTEXT.md): receives and tracks customer orders +- [Billing](./src/billing/CONTEXT.md): generates invoices and processes payments +- [Fulfillment](./src/fulfillment/CONTEXT.md): manages warehouse picking and shipping ## Relationships diff --git a/.github/skills/grill-me/SKILL.md b/.github/skills/grill-me/SKILL.md index f3bd39c1..da7a1e00 100644 --- a/.github/skills/grill-me/SKILL.md +++ b/.github/skills/grill-me/SKILL.md @@ -23,7 +23,7 @@ instead. - Ask questions **one at a time** - For each question, provide your **recommended answer** with brief rationale - If a question can be answered by **exploring the codebase**, explore it instead of asking -- Reference existing ADRs in `docs/adr/` — don't re-litigate settled decisions +- Reference existing ADRs in `docs/adr/`: don't re-litigate settled decisions - Use project domain vocabulary (map-file, provider, facade, etc.) - When a decision crystallizes that contradicts an existing ADR, flag it explicitly - Stop when all branches are resolved or user says "enough" @@ -63,7 +63,7 @@ map points to where each one lives: │ └── docs/adr/ ``` -Create files lazily — only when you have something to write. If no `CONTEXT.md` +Create files lazily: only when you have something to write. If no `CONTEXT.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed. @@ -73,12 +73,12 @@ create it when the first ADR is needed. When the user uses a term that conflicts with the existing language in `CONTEXT.md`, call it out immediately. "Your glossary defines 'cancellation' as -X, but you seem to mean Y — which is it?" +X, but you seem to mean Y: which is it?" ### Sharpen fuzzy language When the user uses vague or overloaded terms, propose a precise canonical term. -"You're saying 'account' — do you mean the Customer or the User? Those are +"You're saying 'account': do you mean the Customer or the User? Those are different things." ### Discuss concrete scenarios @@ -91,12 +91,12 @@ precise about the boundaries between concepts. When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just -said partial cancellation is possible — which is right?" +said partial cancellation is possible: which is right?" ### Update CONTEXT.md inline When a term is resolved, update `CONTEXT.md` right there. Don't batch these -up — capture them as they happen. Use the format in +up: capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md). `CONTEXT.md` should be totally devoid of implementation details. Do not treat @@ -107,10 +107,10 @@ decisions. It is a glossary and nothing else. Only offer to create an ADR when all three are true: -1. **Hard to reverse** — the cost of changing your mind later is meaningful -2. **Surprising without context** — a future reader will wonder "why did they +1. **Hard to reverse**: the cost of changing your mind later is meaningful +2. **Surprising without context**: a future reader will wonder "why did they do it this way?" -3. **The result of a real trade-off** — there were genuine alternatives and you +3. **The result of a real trade-off**: there were genuine alternatives and you picked one for specific reasons If any of the three is missing, skip the ADR. Use the format in diff --git a/.github/skills/python-test-doubles/SKILL.md b/.github/skills/python-test-doubles/SKILL.md index c7a9a298..1fcabbc3 100644 --- a/.github/skills/python-test-doubles/SKILL.md +++ b/.github/skills/python-test-doubles/SKILL.md @@ -11,7 +11,7 @@ This skill defines how to use test doubles in Python (unittest.mock + pytest). ## Test Doubles Types -### 1. Mock — Mock / AsyncMock +### 1. Mock: Mock / AsyncMock Use `Mock` and `AsyncMock` to create mock objects for protocol interfaces. @@ -37,7 +37,7 @@ def async_provider() -> AsyncMock: **MANDATORY:** Always use `spec=InterfaceClass` to catch typos at test time. -### 2. Stub — return_value / side_effect +### 2. Stub: return_value / side_effect Use `return_value` or `side_effect` to configure stubs. @@ -58,7 +58,7 @@ def resolve_secret(name: str) -> str | None: provider.get_secret.side_effect = resolve_secret ``` -### 3. Spy — wraps +### 3. Spy: wraps Use `wraps` to observe calls on real objects without replacing behavior. @@ -74,7 +74,7 @@ sut.resolve_secrets(map_file) spy_parser.parse.assert_called_once_with(map_file) ``` -### 4. Module Patch — patch / patch.object +### 4. Module Patch: patch / patch.object Use `patch` to replace module-level objects or class methods. @@ -100,7 +100,7 @@ def Should_CallSSM_When_AwsProviderUsed(mock_boto: Mock) -> None: mock_ssm.get_parameter.assert_called_once() ``` -### 5. Error Simulation — side_effect with Exception +### 5. Error Simulation: side_effect with Exception Use `side_effect` with an exception to simulate failures. diff --git a/.github/skills/python-testing/SKILL.md b/.github/skills/python-testing/SKILL.md index c2456c35..91a7be56 100644 --- a/.github/skills/python-testing/SKILL.md +++ b/.github/skills/python-testing/SKILL.md @@ -18,7 +18,7 @@ These are **rules**, not guidelines. * **Do NOT write comments** except for AAA markers (`# Arrange`, `# Act`, `# Assert`) * The test name `Should_X_When_Y` already documents the intent -**Exception — SDK public API:** Code under `src/sdks/*/` that is consumed by +**Exception: SDK public API:** Code under `src/sdks/*/` that is consumed by external developers (e.g. facade classes, public entry points) **SHOULD** have docstrings with usage examples. External users rely on IDE tooltips and `help()`. This exception does **not** apply to tests or internal helpers. @@ -60,11 +60,11 @@ class TestUserService: * Each phase **MUST** be separated with comments * **Never mix phases** -* **Each comment (`# Arrange`, `# Act`, `# Assert`) appears AT MOST ONCE per test** — if you need two actions +* **Each comment (`# Arrange`, `# Act`, `# Assert`) appears AT MOST ONCE per test**: if you need two actions or two asserts, write two tests * **No `if`, `switch`, or conditional logic** inside Arrange, Act, or Assert blocks -* **No `try/catch/finally`** inside tests — use pytest fixtures with `yield` for teardown/cleanup -* **No `# Act & Assert` combined blocks** — Act and Assert are ALWAYS separate +* **No `try/catch/finally`** inside tests: use pytest fixtures with `yield` for teardown/cleanup +* **No `# Act & Assert` combined blocks**: Act and Assert are ALWAYS separate * For exception testing, extract the action into a `lambda` before asserting * If no Arrange is needed, omit it * If there is no Assert, the test is invalid @@ -163,7 +163,7 @@ async def Should_ReturnUser_When_UserExists( **Act and Assert MUST be separate.** Extract the action into a `lambda` in the Act phase. -### ✅ CORRECT — separate Act and Assert +### ✅ CORRECT: separate Act and Assert ```python def Should_RaiseValueError_When_NameIsEmpty(sut: GroupService) -> None: @@ -178,7 +178,7 @@ def Should_RaiseValueError_When_NameIsEmpty(sut: GroupService) -> None: action() ``` -### ❌ FORBIDDEN — combined Act & Assert +### ❌ FORBIDDEN: combined Act & Assert ```python def Should_RaiseValueError_When_NameIsEmpty(sut: GroupService) -> None: @@ -196,7 +196,7 @@ def Should_RaiseValueError_When_NameIsEmpty(sut: GroupService) -> None: **Never use `try/finally` in tests.** Use pytest fixtures with `yield` for cleanup. -### ✅ CORRECT — fixture with yield +### ✅ CORRECT: fixture with yield ```python @pytest.fixture() @@ -222,7 +222,7 @@ class TestEnvilderClient: assert os.environ["MY_TOKEN"] == "token-123" ``` -### ❌ FORBIDDEN — try/finally in test +### ❌ FORBIDDEN: try/finally in test ```python def Should_SetEnvVars_When_InjectCalled(self) -> None: diff --git a/.github/skills/python-testing/examples.md b/.github/skills/python-testing/examples.md index b8bf1bfb..ae6b1a63 100644 --- a/.github/skills/python-testing/examples.md +++ b/.github/skills/python-testing/examples.md @@ -1,4 +1,4 @@ -# Python Testing — Real Examples +# Python Testing: Real Examples Examples extracted from the codebase to illustrate patterns described in SKILL.md. diff --git a/.github/skills/python-testing/reference.md b/.github/skills/python-testing/reference.md index 4402e850..26bea558 100644 --- a/.github/skills/python-testing/reference.md +++ b/.github/skills/python-testing/reference.md @@ -1,4 +1,4 @@ -# Python Testing — Quick Reference +# Python Testing: Quick Reference ## pytest Configuration diff --git a/.github/skills/release-coherence/SKILL.md b/.github/skills/release-coherence/SKILL.md index 20cf30e3..8c783de9 100644 --- a/.github/skills/release-coherence/SKILL.md +++ b/.github/skills/release-coherence/SKILL.md @@ -34,16 +34,16 @@ of **any** component: CLI, GitHub Action, or SDK (any runtime). ## Workflow -### Step 1 — Bump Version +### Step 1: Bump Version Update the canonical version source file for the component. -### Step 2 — Changelog Entry +### Step 2: Changelog Entry Add entry to `docs/changelogs/{component}.md` following `doc-maintenance` skill format (categories: Added/Changed/Fixed/Documentation/Dependencies/Security). -### Step 3 — ROADMAP Update (if applicable) +### Step 3: ROADMAP Update (if applicable) Check `ROADMAP.md` for related items: @@ -51,7 +51,7 @@ Check `ROADMAP.md` for related items: - Update version references if roadmap tracks versions - Skip if the release has no roadmap-tracked features -### Step 4 — Website Updates +### Step 4: Website Updates #### For SDKs (delegate to `sdk-release-checklist` if new SDK) @@ -73,16 +73,16 @@ Check `ROADMAP.md` for related items: - [ ] Update `github-action/action.yml` description/inputs - [ ] Update `github-action/README.md` and `docs/github-action.md` -### Step 5 — Cross-Reference Check +### Step 5: Cross-Reference Check - [ ] Root `README.md` reflects current capabilities - [ ] Examples in `examples/sdk/{runtime}/` match current API - [ ] SDK README (`src/sdks/{runtime}/README.md`) matches current API -### Step 6 — Validate +### Step 6: Validate ```bash -# Build website — verifies versions resolve and pages render +# Build website: verifies versions resolve and pages render cd src/website && pnpm build # Run doc-sync skill for comprehensive drift detection @@ -139,6 +139,6 @@ Delegate to `doc-sync` skill for full cross-surface audit if uncertain. |--------------|-----------------| | Hardcoding version in website HTML | Use `__SDK_*_VERSION__` or `__CLI_VERSION__` globals | | Updating changelog but not docs | Always check if behavior/API changed → update docs | -| Updating website but not SDK README | Both must match — SDK README is source of truth for API | -| Skipping i18n for "minor" text changes | All 3 locales must stay in sync — TypeScript catches missing keys | +| Updating website but not SDK README | Both must match: SDK README is source of truth for API | +| Skipping i18n for "minor" text changes | All 3 locales must stay in sync: TypeScript catches missing keys | | Forgetting ROADMAP after completing a tracked feature | Check ROADMAP on every release | diff --git a/.github/skills/sdk-acceptance-testing/SKILL.md b/.github/skills/sdk-acceptance-testing/SKILL.md index 03860ee7..87a7685b 100644 --- a/.github/skills/sdk-acceptance-testing/SKILL.md +++ b/.github/skills/sdk-acceptance-testing/SKILL.md @@ -40,7 +40,7 @@ tests/sdks/{lang}/ ## envilder.json Pattern All SDKs reference the **root** `envilder.json` at the repository root -directly. Container wrappers navigate to it via a relative path — there are no +directly. Container wrappers navigate to it via a relative path: there are no copies per SDK test directory. ```json diff --git a/.github/skills/sdk-implementation-guide/SKILL.md b/.github/skills/sdk-implementation-guide/SKILL.md index d9baed56..90a4e50e 100644 --- a/.github/skills/sdk-implementation-guide/SKILL.md +++ b/.github/skills/sdk-implementation-guide/SKILL.md @@ -59,14 +59,14 @@ Tests mirror the structure under `tests/sdks/{runtime}/`. ## 2. Mandatory API Surface -### Tier 1 — Static Facade (one-liner) +### Tier 1: Static Facade (one-liner) ```txt Envilder.load("map.json") → injects into process env Envilder.resolveFile("map.json") → returns resolved key-value pairs ``` -### Tier 2 — Fluent Builder +### Tier 2: Fluent Builder ```txt Envilder.fromMapFile("map.json") @@ -91,7 +91,7 @@ Envilder.load("production", { | Aspect | Decision | | ------ | -------- | -| Missing secrets | Return null/None/nil (Option in Rust) or omit from result collection — never throw | +| Missing secrets | Return null/None/nil (Option in Rust) or omit from result collection: never throw | | Validation | Opt-in `validateSecrets()` post-resolution | | Cross-provider validation | profile + Azure → error; vaultUrl + AWS → error | | Options override config | Runtime `EnvilderOptions` > `$config` from map file | diff --git a/.github/skills/sdk-release-checklist/SKILL.md b/.github/skills/sdk-release-checklist/SKILL.md index 7fdc976a..ed90e1bc 100644 --- a/.github/skills/sdk-release-checklist/SKILL.md +++ b/.github/skills/sdk-release-checklist/SKILL.md @@ -19,7 +19,7 @@ existing SDK. Prevents drift between code, website, changelogs, and CI. - Auditing that an SDK is fully wired into the website and build system - After a version bump to verify all integration points are updated -## New SDK — Full Checklist +## New SDK: Full Checklist When adding a brand-new SDK to the project, complete **every** item: @@ -43,7 +43,7 @@ Every SDK must have a canonical version source read at build time: | Go | Git tag / `go.mod` convention | `vX.Y.Z` tag | | Java | `pom.xml` or `build.gradle` | `` / `version =` | -### 3. Website — Version Badge Wiring +### 3. Website: Version Badge Wiring The website reads SDK versions at **build time** via `astro.config.mjs`: @@ -55,14 +55,14 @@ The website reads SDK versions at **build time** via `astro.config.mjs`: - [ ] Declare in `src/website/src/env.d.ts`: `declare const __SDK_{RUNTIME}_VERSION__: string;` - [ ] Use dynamic variable in `DocsContent.astro` badge (never hardcode versions) -### 4. Website — Documentation Page Section +### 4. Website: Documentation Page Section - [ ] Add SDK section in `src/website/src/components/DocsContent.astro` (install command, quick start code, badge, link to full docs) - [ ] Add i18n keys to `src/website/src/i18n/types.ts` for all new strings - [ ] Add translations to every locale file: `en.ts`, `ca.ts`, `es.ts` -### 5. Website — Changelog Integration +### 5. Website: Changelog Integration - [ ] Create `docs/changelogs/sdk-{runtime}.md` with initial release entry - [ ] Read changelog in `astro.config.mjs` via `readChangelog()` helper @@ -73,11 +73,11 @@ The website reads SDK versions at **build time** via `astro.config.mjs`: - `src/website/src/pages/ca/changelog.astro` - `src/website/src/pages/es/changelog.astro` - [ ] Add sidebar nav block (button + version list) in the SDKs group for - **all 3** changelog pages — maintain correct `parsed[N]` indices + **all 3** changelog pages: maintain correct `parsed[N]` indices - [ ] Add i18n key `categorySdk{Runtime}` to `types.ts` and all locale files - [ ] Add to mobile product selector dropdown (automatic if in `products` array) -### 6. Website — SDK Cards Component +### 6. Website: SDK Cards Component - [ ] Add card in `src/website/src/components/Sdks.astro` with install command and package manager link @@ -95,7 +95,7 @@ The website reads SDK versions at **build time** via `astro.config.mjs`: - [ ] Add to `docs/changelogs/` index if one exists - [ ] Run `doc-sync` skill to verify alignment -## Existing SDK — Version Bump Checklist +## Existing SDK: Version Bump Checklist When releasing a new version of an already-wired SDK: @@ -132,5 +132,5 @@ node -e "const h=require('fs').readFileSync('dist/changelog/index.html','utf-8') | Hardcoded version in badge | Always use `__SDK_*_VERSION__` globals | | Missing changelog sidebar entry | Check all 3 locale pages, not just `en` | | Wrong `parsed[N]` index after adding SDK | Count products array entries carefully | -| Forgot i18n key in one locale | Add to `types.ts` first — TypeScript errors catch missing keys | +| Forgot i18n key in one locale | Add to `types.ts` first: TypeScript errors catch missing keys | | Version not updating after bump | Restart dev server (Vite caches `define` values) | diff --git a/.github/skills/to-issues/SKILL.md b/.github/skills/to-issues/SKILL.md index 1a6b70cc..9b7fc88b 100644 --- a/.github/skills/to-issues/SKILL.md +++ b/.github/skills/to-issues/SKILL.md @@ -2,7 +2,7 @@ name: to-issues description: >- Break a plan or feature into vertical-slice GitHub issues. Each issue is a - tracer bullet — independently deliverable, testable, and mergeable. + tracer bullet: independently deliverable, testable, and mergeable. Use when decomposing work from ROADMAP.md, a PRD, or a conversation. --- @@ -20,7 +20,7 @@ scope and boundaries. Check ROADMAP.md and existing issues for overlap. ### 2. Slice Vertically -Each issue must be a **tracer bullet** — a thin vertical slice that: +Each issue must be a **tracer bullet**: a thin vertical slice that: - Touches all necessary layers (domain → application → infrastructure → entry point) - Is independently testable and mergeable @@ -65,7 +65,7 @@ Show the full issue list as a numbered table before creating anything: ```text | # | Title | Scope | Depends On | |---|-------|-------|------------| -| 1 | feat(sdk-dotnet): add ISecretProvider port | Domain | — | +| 1 | feat(sdk-dotnet): add ISecretProvider port | Domain | n/a | | 2 | feat(sdk-dotnet): implement AWS SSM provider | Infra | #1 | ``` @@ -73,8 +73,8 @@ Wait for user confirmation. Then create issues via `gh issue create`. ## Rules -- **Max 8 issues per plan** — if more are needed, split into phases -- **Each issue ≤ 1 day of work** — if larger, slice thinner +- **Max 8 issues per plan**: if more are needed, split into phases +- **Each issue ≤ 1 day of work**: if larger, slice thinner - Use Conventional Commit format for titles - Reference ADRs in technical notes when relevant - Label issues with `needs-triage` unless user specifies otherwise diff --git a/.github/skills/typescript-cdk-testing/SKILL.md b/.github/skills/typescript-cdk-testing/SKILL.md index 5185d842..edc4a7b3 100644 --- a/.github/skills/typescript-cdk-testing/SKILL.md +++ b/.github/skills/typescript-cdk-testing/SKILL.md @@ -81,8 +81,8 @@ function normalizeTemplate(template: Template): object { **Normalize these properties:** -- `S3Key` — Lambda deployment artifact hash -- `SourceObjectKeys` — Asset hashes +- `S3Key`: Lambda deployment artifact hash +- `SourceObjectKeys`: Asset hashes - Any `Fn::Join` with account-specific values ### Updating Snapshots @@ -96,7 +96,7 @@ pnpm test -- -u **Rules:** - Review snapshot diffs carefully before approving -- Never update snapshots to suppress failures — understand the change first +- Never update snapshots to suppress failures: understand the change first - Commit updated snapshots alongside the code that caused the change ## Fine-Grained Assertions (Secondary Pattern) @@ -155,11 +155,11 @@ describe("LambdaStack", () => { | Scenario | Pattern | | --- | --- | -| New stack or construct | **Snapshot** — captures full baseline | -| Specific security property (e.g., encryption) | **Assertion** — explicit check won't be missed | -| Resource count verification | **Assertion** — `resourceCountIs` | -| Cross-resource references | **Assertion** — verify `Ref`/`Fn::GetAtt` | -| Infrastructure refactor (same output) | **Snapshot** — confirms no drift | +| New stack or construct | **Snapshot**: captures full baseline | +| Specific security property (e.g., encryption) | **Assertion**: explicit check won't be missed | +| Resource count verification | **Assertion**: `resourceCountIs` | +| Cross-resource references | **Assertion**: verify `Ref`/`Fn::GetAtt` | +| Infrastructure refactor (same output) | **Snapshot**: confirms no drift | | Config-driven resource creation | **Snapshot** + **assertion** for critical properties | ## Test Naming @@ -173,7 +173,7 @@ it("Should_CreateDeadLetterQueue_When_SqsHasMaxReceiveCount", ...) it("Should_RestrictPublicAccess_When_S3BucketIsCreated", ...) ``` -## Test Data — Config Objects +## Test Data: Config Objects Use realistic config objects that match the config-driven infrastructure pattern: diff --git a/.github/skills/typescript-test-doubles/SKILL.md b/.github/skills/typescript-test-doubles/SKILL.md index 6ff118a8..5af8a523 100644 --- a/.github/skills/typescript-test-doubles/SKILL.md +++ b/.github/skills/typescript-test-doubles/SKILL.md @@ -11,7 +11,7 @@ This skill defines how to use test doubles in TypeScript (Vitest). ## Test Doubles Types -### 1. Mock — vi.fn() +### 1. Mock: vi.fn() Use `vi.fn()` to create mock functions for port interfaces. @@ -34,7 +34,7 @@ const mockLogger: ILogger = { }; ``` -### 2. Stub — mockResolvedValue / mockReturnValue +### 2. Stub: mockResolvedValue / mockReturnValue Use return value methods to configure stubs. @@ -54,7 +54,7 @@ mockProvider.getSecret .mockResolvedValueOnce('second'); ``` -### 3. Spy — vi.spyOn() +### 3. Spy: vi.spyOn() Use `vi.spyOn()` to observe calls on real objects without replacing behavior. @@ -69,7 +69,7 @@ expect(spy).toHaveBeenCalledWith('Processing...'); spy.mockRestore(); ``` -### 4. Module Mock — vi.mock() +### 4. Module Mock: vi.mock() Use `vi.mock()` to replace entire modules. @@ -84,7 +84,7 @@ vi.mock('@aws-sdk/client-ssm', () => ({ })); ``` -### 5. Error Simulation — mockRejectedValue +### 5. Error Simulation: mockRejectedValue Use `mockRejectedValue()` to simulate failures. diff --git a/.github/skills/typescript-testing/SKILL.md b/.github/skills/typescript-testing/SKILL.md index c2533aef..b8e8afa2 100644 --- a/.github/skills/typescript-testing/SKILL.md +++ b/.github/skills/typescript-testing/SKILL.md @@ -14,11 +14,11 @@ These are **rules**, not guidelines. ### NO Comments Except AAA Markers -* **Do NOT write explanatory comments** — code must be self-explanatory +* **Do NOT write explanatory comments**: code must be self-explanatory * **Only `// Arrange`, `// Act`, `// Assert`** comments are allowed in tests * The test name `Should_X_When_Y` already documents the intent -**Exception — SDK public API:** Code under `src/sdks/*/` consumed by +**Exception: SDK public API:** Code under `src/sdks/*/` consumed by external developers (facade classes, public entry points) **SHOULD** have JSDoc with usage examples. This exception does **not** apply to tests or internal helpers. @@ -48,19 +48,19 @@ internal helpers. * Each phase **MUST** be separated with comments * **Never mix phases** * **Each comment (`// Arrange`, `// Act`, `// Assert`) appears AT MOST ONCE - per test** — if you need two actions or two asserts, write two tests + per test**: if you need two actions or two asserts, write two tests * **Act = one single invocation on the SUT.** Multiple statements in Act only if they are genuinely part of the same logical action (rare and exceptional). Two independent operations = two tests. * **All assertions belong in Assert only.** No `expect()` in Arrange or Act. If you feel tempted to assert in Arrange (precondition check), extract it to - a separate test or use a guard clause that throws — not an assertion. -* **AAA markers are mandatory in ALL tests** — including structural guards, + a separate test or use a guard clause that throws: not an assertion. +* **AAA markers are mandatory in ALL tests**: including structural guards, static completeness checks, and data validation tests. No exceptions. * **No `if`, `switch`, or conditional logic** inside Arrange, Act, or Assert -* **No `try/catch/finally`** inside tests — use `beforeEach`/`afterEach` for +* **No `try/catch/finally`** inside tests: use `beforeEach`/`afterEach` for teardown -* **No `// Act & Assert` combined blocks** — Act and Assert are ALWAYS separate +* **No `// Act & Assert` combined blocks**: Act and Assert are ALWAYS separate * For exceptions: `expect(() => action()).toThrow()` or `await expect(asyncAction()).rejects.toThrow()` * Omit comment if section is empty @@ -164,7 +164,7 @@ expect(mockLogger.info).toHaveBeenCalledWith(expect.stringContaining('success')) **Act and Assert MUST be separate.** Wrap the action in Act, assert in Assert. -### ✅ CORRECT — separate Act and Assert +### ✅ CORRECT: separate Act and Assert ```typescript it('Should_ThrowInvalidArgument_When_ProviderIsUnsupported', () => { @@ -179,7 +179,7 @@ it('Should_ThrowInvalidArgument_When_ProviderIsUnsupported', () => { }); ``` -### ✅ CORRECT — async exceptions +### ✅ CORRECT: async exceptions ```typescript it('Should_ThrowParameterNotFound_When_SSMKeyIsMissing', async () => { @@ -194,7 +194,7 @@ it('Should_ThrowParameterNotFound_When_SSMKeyIsMissing', async () => { }); ``` -### ❌ FORBIDDEN — combined Act & Assert +### ❌ FORBIDDEN: combined Act & Assert ```typescript it('Should_ThrowError_When_Invalid', () => { diff --git a/.github/skills/website-content-strategy/SKILL.md b/.github/skills/website-content-strategy/SKILL.md index ca287882..c79618be 100644 --- a/.github/skills/website-content-strategy/SKILL.md +++ b/.github/skills/website-content-strategy/SKILL.md @@ -27,7 +27,7 @@ environment variables from AWS SSM Parameter Store or Azure Key Vault. ### Three core problems solved -1. **Security**: Secrets never live in `.env` files, git repos, or CI logs — +1. **Security**: Secrets never live in `.env` files, git repos, or CI logs; fetched from cloud vault at runtime 2. **Consistency**: One `envilder.json` = single source of truth for all environments (dev, staging, production) @@ -43,14 +43,14 @@ Developers want to know **how it works** and **how to use it quickly**. - Show real CLI commands and `envilder.json` examples - Explain `--exec` mode, push mode, and GitHub Action inputs - Use terminal mockups (`TerminalMockup.astro`) for live demos -- Keep language direct and concise — no marketing fluff +- Keep language direct and concise: no marketing fluff - Include code blocks with copy buttons - Show common workflows (local dev, CI/CD, team onboarding) ### Key selling points - One command replaces manual secret management -- Works with existing `.env` workflows — zero migration cost +- Works with existing `.env` workflows: zero migration cost - Supports `--exec` mode to inject secrets without writing files - Type-safe configuration via `envilder.json` - Works locally, in CI, and in production @@ -73,8 +73,8 @@ Leaders want to know **business impact** and **risk reduction**. - Zero secrets in source control (compliance-ready) - Multi-cloud support (AWS SSM + Azure Key Vault) without vendor lock-in - GitHub Action integration for CI/CD pipelines with no code changes -- Open-source with MIT license — no licensing costs -- Hexagonal architecture — easy to extend with new providers +- Open-source with MIT license: no licensing costs +- Hexagonal architecture: easy to extend with new providers - Runtime SDKs (.NET, Python, Node.js) for direct app integration ## Content Patterns @@ -105,6 +105,6 @@ concern (security, DX, compliance, multi-cloud). - Never invent features not present in code - Never make unverifiable performance claims -- Keep technical accuracy — verify against actual CLI flags and behavior +- Keep technical accuracy: verify against actual CLI flags and behavior - Balance both audiences on the same page (don't alienate either) - Product names and CLI flags stay in English (see `website-i18n` skill) diff --git a/.github/skills/website-design-system/SKILL.md b/.github/skills/website-design-system/SKILL.md index c7e7e228..dad0ff84 100644 --- a/.github/skills/website-design-system/SKILL.md +++ b/.github/skills/website-design-system/SKILL.md @@ -30,7 +30,7 @@ The site uses `data-theme` attribute on ``. Two themes are supported: ### Rules -- **All colors MUST use CSS variables** — never hardcode hex values +- **All colors MUST use CSS variables**: never hardcode hex values - New variables MUST be defined in **both** `:root` (retro) and `[data-theme="light"]` blocks in `global.css` - Never modify the theme switcher mechanism or its localStorage key @@ -101,10 +101,10 @@ Reuse existing CSS classes for visual consistency: ## Constraints -- DO NOT install CSS frameworks or UI libraries — use existing pure CSS -- DO NOT hardcode colors — always CSS variables from `global.css` -- DO NOT use fixed pixel font sizes — use `clamp()` or relative units +- DO NOT install CSS frameworks or UI libraries: use existing pure CSS +- DO NOT hardcode colors: always CSS variables from `global.css` +- DO NOT use fixed pixel font sizes: use `clamp()` or relative units - DO NOT break existing responsive layouts when adding new sections -- DO NOT add JavaScript frameworks (React, Vue) — Astro components + +- DO NOT add JavaScript frameworks (React, Vue): Astro components + `