Skip to content

Latest commit

 

History

History
2624 lines (1835 loc) · 127 KB

File metadata and controls

2624 lines (1835 loc) · 127 KB

AGENTS.md

NOTE: This file is generated from:

  • .github/copilot-instructions.md
  • .github/instructions/general-code-change.instructions.md
  • .github/instructions/general-unit-test.instructions.md
  • .github/instructions/codexer.instructions.md
  • .github/instructions/csharp-code-change.instructions.md
  • .github/instructions/csharp-unit-test.instructions.md
  • .github/instructions/github-actions-ci-cd-best-practices.instructions.md
  • .github/instructions/github-actions.instructions.md
  • .github/instructions/powershell-code-change.instructions.md
  • .github/instructions/powershell-unit-test.instructions.md
  • .github/instructions/python-code-change.instructions.md
  • .github/instructions/python-suppressions.instructions.md
  • .github/instructions/python-unit-test.instructions.md
  • .github/instructions/self-explanatory-code-commenting.instructions.md
  • .github/instructions/typescript-code-change.instructions.md
  • .github/instructions/typescript-suppressions.instructions.md
  • .github/instructions/typescript-unit-test.instructions.md

Do not edit this file manually. To update policies, edit the source *.instructions.md files and .github/copilot-instructions.md, then run:

pwsh -File scripts/dev-tools/sync-agents-from-instructions.ps1

Repository Setup (High-Level)

  • For coding and testing policies, always follow the sections below in the order: Copilot instructions -> general policies -> language-specific policies -> CI policies.
  • Use the language- and domain-specific sections for Python, PowerShell, and CI behavior.

Repository Instructions (GitHub Copilot Canonical)

Copilot Instructions

Project Guidelines

  • Repository uses instruction files under .github/instructions, including csharp-code-change policy requiring environment-appropriate C# commands and strict toolchain order.
  • C# tests should use MSTest as the framework, with Moq for mocking and FluentAssertions for assertions.

Tone Policy

  • Use a strictly professional, factual, and neutral tone in all user-facing responses.
  • Do not use jokes, humor, metaphors, playful analogies, emojis, GIFs, banter, or conversational filler.
  • Avoid motivational hype or theatrical phrasing.
  • If wording sounds informal or playful, rewrite it in neutral business language.

Agent Code Change Policy

Agent Code Change Policy

CRITICAL: When implementing any any code, tests, tasks, or scripts, you must adhere to these repo policies without exception. This includes but is not limited to adding, removing, or changing any code, tasks, scripts, modules, packages, tests or their components.

Language-specific standards (e.g. for Python) are defined in additional instructions files and layer on top of this general policy.

Before Making Changes

  • Clarify the objective. Begin reasoning from clearly stated assumptions or axioms.
  • Read existing change plans (e.g., change-plan.md).
  • Document the plan to make changes. If it is part of an existing change plan, make any relevant updates to the plan before executing.

Bugfix Workflow (all languages, defects only)

Use this workflow only when addressing a bug or defect. Feature work, refactors, and new capabilities should follow the general planning steps and design principles rather than this bugfix sequence.

  1. Create a failing regression test first

    • Add the smallest deterministic test that reproduces the bug using the project’s standard test layout (prefer the module’s existing test file; use tests/bugs/<YYYY>/<issue>-<desc>.py only when no clear home exists).
    • Ensure the test fails before the fix and will pass after; avoid external services or temporary files.
  2. Implement the minimal, targeted fix

    • Change only what is needed to make the failing test pass; keep boundaries intact and avoid opportunistic refactors.
    • If you uncover deeper design problems, open a new issue instead of widening scope; add logging only when it materially aids diagnosis.
  3. Verify locally before review

    • Re-run the original repro and the new regression test.
    • Run the full toolchain in order (format → lint → type-check → test) using the repo-standard commands or tasks; rerun from the start if any step changes files or fails.

1. Design Principles

High-level design priorities (applies to all languages):

  1. Simplicity first

    • Prefer the simplest design that works and is easy to read.
    • Avoid cleverness and deep indirection. The next maintainer should be able to understand a module in one reading.
  2. Reusability

    • Factor out logic that is clearly reusable into small methods or pure functions.
    • Avoid copy-paste; share behavior via composition, helper methods, or shared base classes/interfaces.
  3. Extensibility

    • Design public APIs so they can be extended without breaking callers:
      • Prefer keyword-style parameters with defaults (or equivalent in the language).
      • Prefer composition over inheritance when possible.
      • Use interfaces/abstract types/protocols to support multiple implementations behind an interface.
  4. Separation of concerns

    • Keep pure logic (transforms, calculations, parsing) separate from:
      • I/O (disk, network, DB)
      • UI / CLI
      • Framework-specific glue
    • Orchestration code (e.g., “main” pipeline classes) may depend on many things; pure core logic should depend on very little.

2. Classes, Functions, and APIs

Overall rule:
Use strongly-typed, well-structured classes to model domain concepts and workflows. Use functions (or equivalent) for small, stateless helpers and glue code.

2.1 Prefer classes for domain concepts and workflows

Create a class when at least one is true:

  • There is a clear domain concept with data + behavior
    • e.g. “transaction”, “corpus”, “contact matcher”, “pipeline”.
  • You have state + invariants that should travel together
    • e.g. a model that must keep weights, vocabulary, and metadata in sync.
  • You expect multiple implementations behind a common interface
    • e.g. different text sources, storage backends, or pipelines.
  • You are modeling a multi-step workflow that shares context
    • e.g. download(), normalize(), index(), export() steps on a pipeline object.

When you use classes:

  • Keep methods small and focused; a method should do one conceptual thing.
  • Avoid “god objects” that know about too many unrelated concerns.

2.2 Use functions for small, pure helpers

Create a standalone function when:

  • The operation is pure, stateless, and simple:
    • e.g. “normalize whitespace in this string”
    • e.g. “compute a score from inputs”
  • It’s a small helper that doesn’t naturally belong on a specific domain class.
  • It is a simple transformation from inputs to outputs.

Rules for functions:

  • Functions should be short, readable, and clearly named by what they do.
  • Avoid long, deeply branching functions—factor logic into smaller helpers.

2.3 Interfaces and contracts

  • Use interfaces / abstract types / protocols when multiple implementations are likely (e.g. different storage backends or text sources).
  • Public methods and functions must have clear, documented contracts (inputs, outputs, invariants).

3. Error Handling, Logging, and Contracts

  1. Error handling

    • Fail fast and explicitly: raise or return clear, specific errors when invariants are violated.
    • Don’t silently ignore errors or broad-catch (e.g. a “catch all”) unless you immediately re-raise or propagate with added context.
  2. Logging

    • Use the project’s logging pattern instead of ad-hoc print/console output.
    • Log at appropriate levels (debug, info, warning, error) and include enough context to debug issues.
  3. Contracts / invariants

    • Enforce invariants at construction/initialization time.
    • Use assertions only for internal sanity checks, not user-facing error handling.

4. Module & File Structure

  1. Keep modules cohesive:

    • A module/file should have a clear purpose (e.g. “QIF parsing,” “Lexile model,” “corpus download”).
    • Avoid dumping unrelated classes/functions into the same file.
    • Do not exceed 500 lines for any one file.
    • This 500-line limit applies to production code, test code, and reusable scripts.
    • Exceptions: temporary throwaway scripts created and deleted during an agent session; raw text fixtures used for language-processing test data; Markdown documentation files.
  2. Public vs internal

    • Make the public surface area small and intentional.
    • Use “internal” helpers and naming conventions (e.g. underscore-prefix or equivalent) for things that should not be used outside the module.
  3. Imports / dependencies

    • Prefer clear, explicit imports within the project.
    • Avoid circular dependencies; if they appear, refactor shared logic into a lower-level module.

5. Naming, Docs, and Comments

  1. Naming

    • Names should be descriptive, not cryptic.
    • Abbreviations are okay only when they are standard and widely understood (e.g. id, url, db).
  2. Docs / docstrings

    • Public classes and methods should have a short description covering:
      • What it does.
      • Important arguments/parameters.
      • What it returns or side effects.
  3. Comments

    • Comment why, not what. The code should generally explain what.
    • If you use workarounds or non-obvious patterns, add a short comment explaining the reasoning.

6. Performance, I/O, and Dependencies

  1. Performance

    • Prefer clarity first; optimize only where there is a demonstrated need.
    • Avoid obviously quadratic (O(N²)) or worse algorithms on large inputs unless justified.
  2. I/O boundaries

    • Isolate I/O (disk, network, APIs) into specific classes or modules.
    • Core domain logic should be testable without touching the network or filesystem.
    • Use of temporary files within tests is strictly prohibited.
  3. Dependencies

    • Use only the libraries already approved in the project unless specifically told to add more.
    • If adding a dependency is unavoidable, choose a well-maintained, widely used package, and document why it’s required.

7. How to Interact with Existing Code

  1. Follow existing patterns

    • Where the repo already has a clear style (e.g. how pipelines or models are structured), match that style.
    • If you need to improve an existing pattern, keep it compatible with current usages.
  2. API changes

    • Avoid breaking public APIs. If a breaking change is necessary, call it out clearly in comments or the PR description.
  3. Tests as specification

    • Treat existing unit tests as part of the spec.
    • When adding new behavior, add tests that make the behavior explicit (using the language’s standard test framework).

8. After Making Changes

1. Run the full toolchain (no shortcuts)

You must run the full toolchain in this exact order and repeat it until everything passes:

  1. Formatting
  2. Linting
  3. Type checking
  4. Testing

Treat these four steps as one toolchain pass.

  1. Run the formatter on the relevant files (e.g. Black).

  2. Run the linter (e.g. Ruff).

    • If the linter fails or auto-fixes anything:
      • Fix all reported issues (including applying any auto-fixes).
      • Then restart the toolchain pass from step 1 (Formatting).
  3. Run the type checker (e.g. Pyright).

    • If type checking fails:
      • Fix all reported issues.
      • Then restart the toolchain pass from step 1 (Formatting).
  4. Run the tests (e.g. Pytest).

    • If any test fails:
      • Fix all reported issues.
      • Then restart the toolchain pass from step 1 (Formatting).

You may not stop this loop while any of the following are true:

  • Formatting would change the code.
  • Linting reports errors.
  • Type checking reports errors.
  • Tests fail.

Only when all four steps complete without errors in a single pass are you allowed to consider the change complete.

When you report back, explicitly state:

  • Which formatting, linting, type-checking, and test commands you ran, and
  • That all four steps passed without errors in the final pass.

2. Summarize key changes and rationale

  • Summarize the key changes made and how they relate to the original objective.
  • Explain any important design choices and other options you considered but did not implement.

3. Update supporting documents

  • Update any supporting documents (e.g., README, design docs, runbooks).
  • Update any workplan, change plan, or instructions document to show progress and reflect the new behavior.

4. Provide clear next steps

  • Provide clear development next steps (what should happen next, and by whom).
  • If development is complete, provide detailed instructions on usage and any operational caveats (limits, known issues, rollout steps).

General Unit Test Policy

applyTo: "**" name: general-unit-test-policy description: "Baseline unit test policy that applies to all languages in this repo"

General Unit Test Policy

This policy applies to all unit tests in this repository, regardless of language or framework.

Every new or modified unit test must adhere to these guidelines.


1. Core Principles

  • Independence
    Tests must be able to run in any order without impacting each other.

  • Isolation
    Each unit test should target a single function, method, or unit of behavior so failures clearly identify the faulty unit.

  • Fast Execution
    Tests must be fast enough to support frequent runs and rapid feedback loops.

  • Determinism
    Given the same inputs and environment, tests must produce the same results. Avoid flakiness.

  • Readability and Maintainability
    Test names, structure, and assertions should be clear and easy to understand.


2. Coverage and Scenarios

  • Comprehensive Coverage (within reason)

    • These coverage expectations apply across all languages in the repo.
    • Aim to exercise critical paths and important edge conditions.
    • Configure coverage tooling to exclude test files (e.g., tests/), so metrics reflect the application code, not the tests themselves.
    • Repository-wide line coverage must remain >= 80%.
    • Any new modules, classes, or methods added must target >= 90% coverage.
    • Code changes or refactors must not reduce coverage for the lines that were changed.
    • Coverage is a supporting metric, not the sole quality gate; untested critical behavior is not acceptable even if the overall percentage looks good.
  • Scenario Completeness
    For each unit or behavior, tests should cover:

    • Positive flows with valid inputs.
    • Negative flows for invalid or missing inputs.
    • Edge cases and boundary conditions.
    • Error-handling behavior.
    • Concurrency behavior when relevant.
    • State transitions for stateful components.

3. Test Structure and Diagnostics

  • Clear Failure Messages
    Assertions should produce clear, actionable failure messages that make it easy to see what went wrong.

  • Arrange–Act–Assert pattern
    Organize tests into:

    • Arrange — set up inputs, environment, and dependencies.
    • Act — execute the behavior under test.
    • Assert — verify outcomes via assertions.
  • Document Intent
    Each test must clearly communicate its purpose:

    • Use descriptive test names, and/or
    • Include a short docstring or comment summarizing the scenario and expected outcome.

4. External Dependencies and Environment

  • Avoid External Dependencies
    Unit tests must not depend on external services such as databases, networks, remote APIs, or external processes.

  • Use Mocks / Stubs as Needed
    When code interacts with external systems or heavy resources, use mocks, stubs, or fakes to isolate the unit under test.

  • Environment Stability
    Tests must not rely on mutable global state or external configuration that can change between runs. Creation and use of temporary files on the local filesystem is expressly prohibited unless explicitly authorized as an exception.

    • Currently approved exceptions: none.
    • If an exception is ever approved, list it explicitly here. A possible future example would be a static, read-only sample file committed to the repo and reused without runtime creation; this is not approved today.

5. Policy Audit

Before submitting any change that includes unit tests:

  • Review each new or modified test against this policy.
  • Confirm that:
    • It is independent, isolated, fast, and deterministic.
    • It is readable and clearly documents its intent.
    • It covers relevant positive, negative, edge, and error scenarios.
    • It does not rely on external dependencies without proper mocking/stubbing.

If any test cannot comply with these rules for a good reason, call out the exception explicitly in the change description.

Codexer Instructions (Placeholder)

Codexer Instructions (Placeholder)

This file is a placeholder to satisfy agent synchronization tooling.

C# Code Change Policy

C# Code Change Policy

You must:

  • Apply all rules in the general code change policy.
  • Apply all C#-specific rules in this file.
  • Apply the unit test policies (general-unit-test.instructions.md and csharp-unit-test.instructions.md) for any work involving tests.

1. Tooling & Baseline for C#

These are the required tools for C# code in this repo:

  1. Formatting — csharpier

    • All C# source files (*.cs) must be formatted with csharpier.
    • Do not use dotnet format — it loads the solution/project model and can mis-handle legacy VSTO / .NET Framework projects by rewriting .csproj files.
    • csharpier is file-based and formats only *.cs without touching project files.
    • Do not hand-format; if a diff disagrees with csharpier, formatter output wins.
    • Approved commands:
      • dotnet tool run csharpier .
      • or csharpier . (if installed globally)
  2. Linting / Static Analysis — .NET analyzers

    • C# code must pass Roslyn/.NET analyzer diagnostics configured by .editorconfig, .globalconfig, and project properties.
    • Enforce analyzer diagnostics in build using EnableNETAnalyzers and EnforceCodeStyleInBuild.
    • Prefer fixing diagnostics over suppressing them.
    • Approved commands (Windows; choose the variant for your shell):
      • CMD / Developer Command Prompt: msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform="Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true
      • PowerShell: msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform='Any CPU' /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true
  3. Type Checking — C# compiler + nullable analysis

    • Treat C# compiler diagnostics and nullable-flow warnings as first-class type-safety checks.
    • Enable nullable reference types and fail builds on warnings for touched code paths.
    • Avoid introducing nullable warnings; fix the root null-state issue instead.
    • Approved commands (Windows; choose the variant for your shell):
      • CMD / Developer Command Prompt: msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform="Any CPU" /p:Nullable=enable /p:TreatWarningsAsErrors=true
      • PowerShell: msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform='Any CPU' /p:Nullable=enable /p:TreatWarningsAsErrors=true

Testing tools and behavior are defined in the unit test policies. Do not define test behavior here; instead, obey general-unit-test.instructions.md and csharp-unit-test.instructions.md.


2. C# Design & Type-Safety Principles

These refine the general design principles for C# code.

  1. Strong contracts and explicit APIs

    • Public methods, constructors, and properties must express clear contracts.
    • Use explicit types at public boundaries; use var only when the type is obvious.
  2. Null-safety by default

    • Keep nullable reference types enabled.
    • Model optional values explicitly with nullable annotations and guard clauses.
    • Use nullability attributes where needed to improve flow analysis.
  3. Prefer composition and focused types

    • Keep classes cohesive and scoped to one core responsibility.
    • Favor composition over inheritance unless polymorphism is a clear requirement.
  4. Asynchrony and resource safety

    • Use async/await for I/O-bound operations.
    • Prefer using/await using for disposable resources.

3. Classes, Methods, and APIs (C#-Specific Guidance)

3.1 Classes for domain concepts and workflows

Use classes/records when:

  • Modeling domain concepts with state + behavior.
  • Protecting invariants across related members.
  • Providing multiple implementations behind interfaces.
  • Orchestrating multi-step workflows that share context.

When using classes/records:

  • Keep methods small and focused.
  • Avoid god objects.
  • Prefer immutable records/value objects for data-centric models where practical.

3.2 Methods and local functions for focused logic

Use methods/local functions when:

  • Implementing narrow, deterministic behavior.
  • Encapsulating reusable, stateless transformations.

Rules:

  • Name methods by behavior.
  • Keep branching shallow where possible.
  • Extract helper methods instead of deeply nested conditionals.

3.3 Interfaces and contracts

  • Use interfaces when multiple implementations are expected.
  • Keep public APIs stable and avoid unnecessary breaking changes.
  • Document non-obvious side effects and failure modes.

4. Error Handling, Logging, and Contracts (C#)

  1. Exceptions

    • Fail fast with explicit exceptions when invariants are violated.
    • Avoid catching broad Exception unless at a clear boundary and with added context.
  2. Logging

    • Use the repository/project logging pattern, not ad-hoc console output in production code.
    • Log actionable context at appropriate levels.
  3. Contracts / invariants

    • Validate constructor and method preconditions.
    • Use Debug.Assert only for internal invariants, not user-facing validation.

5. Module & File Structure (C#)

  1. Cohesive files and namespaces

    • Keep files focused on one responsibility area.
    • Keep file size under the repo limit in general-code-change.instructions.md.
  2. Public vs internal

    • Keep public surface area intentional and minimal.
    • Prefer internal for non-public APIs.
  3. Imports and namespace hygiene

    • Prefer explicit using directives at file scope.
    • Avoid circular dependencies.

6. Naming, Docs, and Comments (C#)

  1. Naming conventions

    • PascalCase for types and public members.
    • camelCase for local variables and private fields/parameters.
    • Use descriptive names over abbreviations.
  2. Documentation comments

    • Public APIs should include XML documentation comments when behavior or contract is non-obvious.
  3. Comments

    • Comment why, not what.
    • Keep comments synchronized with behavior.

7. Dependencies and Analyzer Configuration (C#)

  • Prefer built-in .NET SDK analyzers and configuration through .editorconfig / .globalconfig.
  • Use project-level properties (EnableNETAnalyzers, AnalysisLevel, AnalysisMode, EnforceCodeStyleInBuild) rather than ad-hoc per-command behavior where possible.
  • Avoid adding external dependencies unless unavoidable and approved by the project direction.
  • If suppression is unavoidable, keep it as narrow as possible and document the rationale in-code.

C# Unit Test Policy

C# Unit Test Policy

  • The general unit test policy, and
  • The C#-specific rules below.

1. Framework Selection

  • Testing framework
    • Use MSTest (Microsoft.VisualStudio.TestTools.UnitTesting) for C# unit tests in this repository.
    • Do not introduce xUnit or NUnit into existing test projects.

2. C#-Specific Libraries and Conventions

  • Mocking library

    • Use Moq for mocks/stubs in C# unit tests.
  • Assertion library

    • Prefer FluentAssertions for new and updated assertions.
    • Use MSTest Assert APIs only when FluentAssertions is not practical for a specific assertion shape.
  • MSTest style

    • Use [TestClass], [TestMethod], and other MSTest attributes from Microsoft.VisualStudio.TestTools.UnitTesting.

3. C# Toolchain Command Selection

  • For C# work, use these concrete commands for the general policy toolchain loop:

    1. csharpier .
    2. msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform="Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true
    3. msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform="Any CPU" /p:Nullable=enable /p:TreatWarningsAsErrors=true
    4. vstest.console.exe <test-assembly-paths> /EnableCodeCoverage
  • The loop behavior (restart rules, must-pass requirements, and audit expectations) is defined by general-code-change.instructions.md and is intentionally not repeated here.

This file is intentionally limited to C#-specific framework/library/tool selection. Cross-language testing principles and policy requirements are defined in general-unit-test.instructions.md and general-code-change.instructions.md.

GitHub Actions CI/CD Best Practices

GitHub Actions CI/CD Best Practices

Your Mission

As GitHub Copilot, you are an expert in designing and optimizing CI/CD pipelines using GitHub Actions. Your mission is to assist developers in creating efficient, secure, and reliable automated workflows for building, testing, and deploying their applications. You must prioritize best practices, ensure security, and provide actionable, detailed guidance.

Core Concepts and Structure

1. Workflow Structure (.github/workflows/*.yml)

  • Principle: Workflows should be clear, modular, and easy to understand, promoting reusability and maintainability.
  • Deeper Dive:
    • Naming Conventions: Use consistent, descriptive names for workflow files (e.g., build-and-test.yml, deploy-prod.yml).
    • Triggers (on): Understand the full range of events: push, pull_request (manual), schedule (cron jobs), repository_dispatch (external events), workflow_call (reusable workflows).
    • Concurrency: Use concurrency to prevent simultaneous runs for specific branches or groups, avoiding race conditions or wasted resources.
    • Permissions: Define permissions at the workflow level for a secure default, overriding at the job level if needed.
  • Guidance for Copilot:
    • Always start with a descriptive name and appropriate on trigger. Suggest granular triggers for specific use cases (e.g., on: push: branches: [main] vs. on: pull_request).
    • Recommend using workflow_dispatch for manual triggers, allowing input parameters for flexibility and controlled deployments.
    • Advise on setting concurrency for critical workflows or shared resources to prevent resource contention.
    • Guide on setting explicit permissions for GITHUB_TOKEN to adhere to the principle of least privilege.
  • Pro Tip: For complex repositories, consider using reusable workflows (workflow_call) to abstract common CI/CD patterns and reduce duplication across multiple projects.

2. Jobs

  • Principle: Jobs should represent distinct, independent phases of your CI/CD pipeline (e.g., build, test, deploy, lint, security scan).
  • Deeper Dive:
    • runs-on: Choose appropriate runners. ubuntu-latest is common, but windows-latest, macos-latest, or self-hosted runners are available for specific needs.
    • needs: Clearly define dependencies. If Job B needs Job A, Job B will only run after Job A successfully completes.
    • outputs: Pass data between jobs using outputs. This is crucial for separating concerns (e.g., build job outputs artifact path, deploy job consumes it).
    • if Conditions: Leverage if conditions extensively for conditional execution based on branch names, commit messages, event types, or previous job status (if: success(), if: failure(), if: always()).
    • Job Grouping: Consider breaking large workflows into smaller, more focused jobs that run in parallel or sequence.
  • Guidance for Copilot:
    • Define jobs with clear name and appropriate runs-on (e.g., ubuntu-latest, windows-latest, self-hosted).
    • Use needs to define dependencies between jobs, ensuring sequential execution and logical flow.
    • Employ outputs to pass data between jobs efficiently, promoting modularity.
    • Utilize if conditions for conditional job execution (e.g., deploy only on main branch pushes, run E2E tests only for certain PRs, skip jobs based on file changes).
  • Example (Conditional Deployment and Output Passing):

3. Steps and Actions

  • Principle: Steps should be atomic, well-defined, and actions should be versioned for stability and security.
  • Deeper Dive:
    • uses: Referencing marketplace actions (e.g., actions/checkout@v4, actions/setup-node@v3) or custom actions. Always pin to a full length commit SHA for maximum security and immutability, or at least a major version tag (e.g., @v4). Avoid pinning to main or latest.
    • name: Essential for clear logging and debugging. Make step names descriptive.
    • run: For executing shell commands. Use multi-line scripts for complex logic and combine commands to optimize layer caching in Docker (if building images).
    • env: Define environment variables at the step or job level. Do not hardcode sensitive data here.
    • with: Provide inputs to actions. Ensure all required inputs are present.
  • Guidance for Copilot:
    • Use uses to reference marketplace or custom actions, always specifying a secure version (tag or SHA).
    • Use name for each step for readability in logs and easier debugging.
    • Use run for shell commands, combining commands with && for efficiency and using | for multi-line scripts.
    • Provide with inputs for actions explicitly, and use expressions (${{ }}) for dynamic values.
  • Security Note: Audit marketplace actions before use. Prefer actions from trusted sources (e.g., actions/ organization) and review their source code if possible. Use dependabot for action version updates.

Security Best Practices in GitHub Actions

1. Secret Management

  • Principle: Secrets must be securely managed, never exposed in logs, and only accessible by authorized workflows/jobs.
  • Deeper Dive:
    • GitHub Secrets: The primary mechanism for storing sensitive information. Encrypted at rest and only decrypted when passed to a runner.
    • Environment Secrets: For greater control, create environment-specific secrets, which can be protected by manual approvals or specific branch conditions.
    • Secret Masking: GitHub Actions automatically masks secrets in logs, but it's good practice to avoid printing them directly.
    • Minimize Scope: Only grant access to secrets to the workflows/jobs that absolutely need them.
  • Guidance for Copilot:
    • Always instruct users to use GitHub Secrets for sensitive information (e.g., API keys, passwords, cloud credentials, tokens).
    • Access secrets via secrets.<SECRET_NAME> in workflows.
    • Recommend using environment-specific secrets for deployment environments to enforce stricter access controls and approvals.
    • Advise against constructing secrets dynamically or printing them to logs, even if masked.
  • Example (Environment Secrets with Approval):

2. OpenID Connect (OIDC) for Cloud Authentication

  • Principle: Use OIDC for secure, credential-less authentication with cloud providers (AWS, Azure, GCP, etc.), eliminating the need for long-lived static credentials.
  • Deeper Dive:
    • Short-Lived Credentials: OIDC exchanges a JWT token for temporary cloud credentials, significantly reducing the attack surface.
    • Trust Policies: Requires configuring identity providers and trust policies in your cloud environment to trust GitHub's OIDC provider.
    • Federated Identity: This is a key pattern for modern, secure cloud deployments.
  • Guidance for Copilot:
    • Strongly recommend OIDC for authenticating with AWS, Azure, GCP, and other cloud providers instead of storing long-lived access keys as secrets.
    • Provide examples of how to configure the OIDC action for common cloud providers (e.g., aws-actions/configure-aws-credentials@v4).
    • Explain the concept of trust policies and how they relate to OIDC setup.
  • Pro Tip: OIDC is a fundamental shift towards more secure cloud deployments and should be prioritized whenever possible.

3. Least Privilege for GITHUB_TOKEN

  • Principle: Grant only the necessary permissions to the GITHUB_TOKEN for your workflows, reducing the blast radius in case of compromise.
  • Deeper Dive:
    • Default Permissions: By default, the GITHUB_TOKEN has broad permissions. This should be explicitly restricted.
    • Granular Permissions: Define permissions at the workflow or job level (e.g., contents: read, pull-requests: write, issues: read).
    • Read-Only by Default: Start with contents: read as the default and add write permissions only when strictly necessary.
  • Guidance for Copilot:
    • Configure permissions at the workflow or job level to restrict access. Always prefer contents: read as the default.
    • Advise against using contents: write or pull-requests: write unless the workflow explicitly needs to modify the repository.
    • Provide a clear mapping of common workflow needs to specific GITHUB_TOKEN permissions.
  • Example (Least Privilege):

4. Dependency Review and Software Composition Analysis (SCA)

  • Principle: Continuously scan dependencies for known vulnerabilities and licensing issues.
  • Deeper Dive:
    • Early Detection: Integrate dependency checks early in the CI pipeline to catch issues before deployment.
    • Tools: Use dependency-review-action, Snyk, Trivy, Mend (formerly WhiteSource).
    • Supply Chain Security: This is a critical component of securing your software supply chain.
  • Guidance for Copilot:
    • Integrate dependency-review-action or other SCA tools into the CI pipeline.
    • Recommend regular scanning for vulnerabilities in third-party libraries and setting up alerts for new findings.
    • Emphasize the importance of maintaining up-to-date dependency lists and understanding transitive dependencies.

5. Static Application Security Testing (SAST)

  • Principle: Identify security vulnerabilities in source code before runtime.
  • Deeper Dive:
    • Shift Left: SAST enables finding and fixing vulnerabilities early in the development lifecycle, which is more cost-effective.
    • Tools: CodeQL, SonarQube, Bandit (Python), ESLint with security plugins (JS/TS).
    • Automated Enforcement: Configure SAST to break builds or block PRs if critical vulnerabilities are found.
  • Guidance for Copilot:
    • Integrate SAST tools (e.g., CodeQL for GitHub Advanced Security, or open-source alternatives) into the CI pipeline.
    • Configure security scanning as a blocking step if critical vulnerabilities are found, enforcing a secure by default posture.
    • Suggest adding security linters or static analysis to pre-commit hooks for earlier feedback.

6. Secret Scanning and Credential Leak Prevention

  • Principle: Prevent secrets from being committed into the repository or exposed in logs.
  • Deeper Dive:
    • GitHub Secret Scanning: Built-in feature to detect secrets in your repository.
    • Pre-commit Hooks: Tools like git-secrets can prevent secrets from being committed locally.
    • Environment Variables Only: Secrets should only be passed to the environment where they are needed at runtime, never in the build artifact.
  • Guidance for Copilot:
    • Suggest enabling GitHub's built-in secret scanning for the repository.
    • Recommend implementing pre-commit hooks that scan for common secret patterns.
    • Advise reviewing workflow logs for accidental secret exposure, even with masking.

7. Immutable Infrastructure & Image Signing

  • Principle: Ensure that container images and deployed artifacts are tamper-proof and verified.
  • Deeper Dive:
    • Reproducible Builds: Ensure that building the same code always results in the exact same image.
    • Image Signing: Use tools like Notary or Cosign to cryptographically sign container images, verifying their origin and integrity.
    • Deployment Gate: Enforce that only signed images can be deployed to production environments.
  • Guidance for Copilot:
    • Advocate for reproducible builds in Dockerfiles and build processes.
    • Suggest integrating image signing into the CI pipeline and verification during deployment stages.

Optimization and Performance

1. Caching GitHub Actions

  • Principle: Cache dependencies and build outputs to significantly speed up subsequent workflow runs.
  • Deeper Dive:
    • Cache Hit Ratio: Aim for a high cache hit ratio by designing effective cache keys.
    • Cache Keys: Use a unique key based on file hashes (e.g., hashFiles('**/package-lock.json'), hashFiles('**/requirements.txt')) to invalidate the cache only when dependencies change.
    • Restore Keys: Use restore-keys for fallbacks to older, compatible caches.
    • Cache Scope: Understand that caches are scoped to the repository and branch.
  • Guidance for Copilot:
    • Use actions/cache@v3 for caching common package manager dependencies (Node.js node_modules, Python pip packages, Java Maven/Gradle dependencies) and build artifacts.
    • Design highly effective cache keys using hashFiles to ensure optimal cache hit rates.
    • Advise on using restore-keys to gracefully fall back to previous caches.
  • Example (Advanced Caching for Monorepo):

2. Matrix Strategies for Parallelization

  • Principle: Run jobs in parallel across multiple configurations (e.g., different Node.js versions, OS, Python versions, browser types) to accelerate testing and builds.
  • Deeper Dive:
    • strategy.matrix: Define a matrix of variables.
    • include/exclude: Fine-tune combinations.
    • fail-fast: Control whether job failures in the matrix stop the entire strategy.
    • Maximizing Concurrency: Ideal for running tests across various environments simultaneously.
  • Guidance for Copilot:
    • Utilize strategy.matrix to test applications against different environments, programming language versions, or operating systems concurrently.
    • Suggest include and exclude for specific matrix combinations to optimize test coverage without unnecessary runs.
    • Advise on setting fail-fast: true (default) for quick feedback on critical failures, or fail-fast: false for comprehensive test reporting.
  • Example (Multi-version, Multi-OS Test Matrix):

3. Self-Hosted Runners

  • Principle: Use self-hosted runners for specialized hardware, network access to private resources, or environments where GitHub-hosted runners are cost-prohibitive.
  • Deeper Dive:
    • Custom Environments: Ideal for large build caches, specific hardware (GPUs), or access to on-premise resources.
    • Cost Optimization: Can be more cost-effective for very high usage.
    • Security Considerations: Requires securing and maintaining your own infrastructure, network access, and updates. This includes proper hardening of the runner machines, managing access controls, and ensuring timely patching.
    • Scalability: Plan for how self-hosted runners will scale with demand, either manually or using auto-scaling solutions.
  • Guidance for Copilot:
    • Recommend self-hosted runners when GitHub-hosted runners do not meet specific performance, cost, security, or network access requirements.
    • Emphasize the user's responsibility for securing, maintaining, and scaling self-hosted runners, including network configuration and regular security audits.
    • Advise on using runner groups to organize and manage self-hosted runners efficiently.

4. Fast Checkout and Shallow Clones

  • Principle: Optimize repository checkout time to reduce overall workflow duration, especially for large repositories.
  • Deeper Dive:
    • fetch-depth: Controls how much of the Git history is fetched. 1 for most CI/CD builds is sufficient, as only the latest commit is usually needed. A fetch-depth of 0 fetches the entire history, which is rarely needed and can be very slow for large repos.
    • submodules: Avoid checking out submodules if not required by the specific job. Fetching submodules adds significant overhead.
    • lfs: Manage Git LFS (Large File Storage) files efficiently. If not needed, set lfs: false.
    • Partial Clones: Consider using Git's partial clone feature (--filter=blob:none or --filter=tree:0) for extremely large repositories, though this is often handled by specialized actions or Git client configurations.
  • Guidance for Copilot:
    • Use actions/checkout@v4 with fetch-depth: 1 as the default for most build and test jobs to significantly save time and bandwidth.
    • Only use fetch-depth: 0 if the workflow explicitly requires full Git history (e.g., for release tagging, deep commit analysis, or git blame operations).
    • Advise against checking out submodules (submodules: false) if not strictly necessary for the workflow's purpose.
    • Suggest optimizing LFS usage if large binary files are present in the repository.

5. Artifacts for Inter-Job and Inter-Workflow Communication

  • Principle: Store and retrieve build outputs (artifacts) efficiently to pass data between jobs within the same workflow or across different workflows, ensuring data persistence and integrity.
  • Deeper Dive:
    • actions/upload-artifact: Used to upload files or directories produced by a job. Artifacts are automatically compressed and can be downloaded later.
    • actions/download-artifact: Used to download artifacts in subsequent jobs or workflows. You can download all artifacts or specific ones by name.
    • retention-days: Crucial for managing storage costs and compliance. Set an appropriate retention period based on the artifact's importance and regulatory requirements.
    • Use Cases: Build outputs (executables, compiled code, Docker images), test reports (JUnit XML, HTML reports), code coverage reports, security scan results, generated documentation, static website builds.
    • Limitations: Artifacts are immutable once uploaded. Max size per artifact can be several gigabytes, but be mindful of storage costs.
  • Guidance for Copilot:
    • Use actions/upload-artifact@v3 and actions/download-artifact@v3 to reliably pass large files between jobs within the same workflow or across different workflows, promoting modularity and efficiency.
    • Set appropriate retention-days for artifacts to manage storage costs and ensure old artifacts are pruned.
    • Advise on uploading test reports, coverage reports, and security scan results as artifacts for easy access, historical analysis, and integration with external reporting tools.
    • Suggest using artifacts to pass compiled binaries or packaged applications from a build job to a deployment job, ensuring the exact same artifact is deployed that was built and tested.

Comprehensive Testing in CI/CD (Expanded)

1. Unit Tests

  • Principle: Run unit tests on every code push to ensure individual code components (functions, classes, modules) function correctly in isolation. They are the fastest and most numerous tests.
  • Deeper Dive:
    • Fast Feedback: Unit tests should execute rapidly, providing immediate feedback to developers on code quality and correctness. Parallelization of unit tests is highly recommended.
    • Code Coverage: Integrate code coverage tools (e.g., Istanbul for JS, Coverage.py for Python, JaCoCo for Java) and enforce minimum coverage thresholds. Aim for high coverage, but focus on meaningful tests, not just line coverage.
    • Test Reporting: Publish test results using actions/upload-artifact (e.g., JUnit XML reports) or specific test reporter actions that integrate with GitHub Checks/Annotations.
    • Mocking and Stubbing: Emphasize the use of mocks and stubs to isolate units under test from their dependencies.
  • Guidance for Copilot:
    • Configure a dedicated job for running unit tests early in the CI pipeline, ideally triggered on every push and pull_request.
    • Use appropriate language-specific test runners and frameworks (Jest, Vitest, Pytest, Go testing, JUnit, NUnit, XUnit, RSpec).
    • Recommend collecting and publishing code coverage reports and integrating with services like Codecov, Coveralls, or SonarQube for trend analysis.
    • Suggest strategies for parallelizing unit tests to reduce execution time.

2. Integration Tests

  • Principle: Run integration tests to verify interactions between different components or services, ensuring they work together as expected. These tests typically involve real dependencies (e.g., databases, APIs).
  • Deeper Dive:
    • Service Provisioning: Use services within a job to spin up temporary databases, message queues, external APIs, or other dependencies via Docker containers. This provides a consistent and isolated testing environment.
    • Test Doubles vs. Real Services: Balance between mocking external services for pure unit tests and using real, lightweight instances for more realistic integration tests. Prioritize real instances when testing actual integration points.
    • Test Data Management: Plan for managing test data, ensuring tests are repeatable and data is cleaned up or reset between runs.
    • Execution Time: Integration tests are typically slower than unit tests. Optimize their execution and consider running them less frequently than unit tests (e.g., on PR merge instead of every push).
  • Guidance for Copilot:
    • Provision necessary services (databases like PostgreSQL/MySQL, message queues like RabbitMQ/Kafka, in-memory caches like Redis) using services in the workflow definition or Docker Compose during testing.
    • Advise on running integration tests after unit tests, but before E2E tests, to catch integration issues early.
    • Provide examples of how to set up service containers in GitHub Actions workflows.
    • Suggest strategies for creating and cleaning up test data for integration test runs.

3. End-to-End (E2E) Tests

  • Principle: Simulate full user behavior to validate the entire application flow from UI to backend, ensuring the complete system works as intended from a user's perspective.
  • Deeper Dive:
    • Tools: Use modern E2E testing frameworks like Cypress, Playwright, or Selenium. These provide browser automation capabilities.
    • Staging Environment: Ideally run E2E tests against a deployed staging environment that closely mirrors production, for maximum fidelity. Avoid running directly in CI unless resources are dedicated and isolated.
    • Flakiness Mitigation: Address flakiness proactively with explicit waits, robust selectors, retries for failed tests, and careful test data management. Flaky tests erode trust in the pipeline.
    • Visual Regression Testing: Consider integrating visual regression testing (e.g., Applitools, Percy) to catch UI discrepancies.
    • Reporting: Capture screenshots and video recordings on failure to aid debugging.
  • Guidance for Copilot:
    • Use tools like Cypress, Playwright, or Selenium for E2E testing, providing guidance on their setup within GitHub Actions.
    • Recommend running E2E tests against a deployed staging environment to catch issues before production and validate the full deployment process.
    • Configure test reporting, video recordings, and screenshots on failure to aid debugging and provide richer context for test results.
    • Advise on strategies to minimize E2E test flakiness, such as robust element selection and retry mechanisms.

4. Performance and Load Testing

  • Principle: Assess application performance and behavior under anticipated and peak load conditions to identify bottlenecks, ensure scalability, and prevent regressions.
  • Deeper Dive:
    • Tools: JMeter, k6, Locust, Gatling, Artillery. Choose based on language, complexity, and specific needs.
    • Integration: Integrate into CI/CD for continuous performance regression detection. Run these tests less frequently than unit/integration tests (e.g., nightly, weekly, or on significant feature merges).
    • Thresholds: Define clear performance thresholds (e.g., response time, throughput, error rates) and fail builds if these are exceeded.
    • Baseline Comparison: Compare current performance metrics against established baselines to detect degradation.
  • Guidance for Copilot:
    • Suggest integrating performance and load testing into the CI pipeline for critical applications, providing examples for common tools.
    • Advise on setting performance baselines and failing the build if performance degrades beyond a set threshold.
    • Recommend running these tests in a dedicated environment that simulates production load patterns.
    • Guide on analyzing performance test results to pinpoint areas for optimization (e.g., database queries, API endpoints).

5. Test Reporting and Visibility

  • Principle: Make test results easily accessible, understandable, and visible to all stakeholders (developers, QA, product owners) to foster transparency and enable quick issue resolution.
  • Deeper Dive:
    • GitHub Checks/Annotations: Leverage these for inline feedback directly in pull requests, showing which tests passed/failed and providing links to detailed reports.
    • Artifacts: Upload comprehensive test reports (JUnit XML, HTML reports, code coverage reports, video recordings, screenshots) as artifacts for long-term storage and detailed inspection.
    • Integration with Dashboards: Push results to external dashboards or reporting tools (e.g., SonarQube, custom reporting tools, Allure Report, TestRail) for aggregated views and historical trends.
    • Status Badges: Use GitHub Actions status badges in your README to indicate the latest build/test status at a glance.
  • Guidance for Copilot:
    • Use actions that publish test results as annotations or checks on PRs for immediate feedback and easy debugging directly in the GitHub UI.
    • Upload detailed test reports (e.g., XML, HTML, JSON) as artifacts for later inspection and historical analysis, including negative results like error screenshots.
    • Advise on integrating with external reporting tools for a more comprehensive view of test execution trends and quality metrics.
    • Suggest adding workflow status badges to the README for quick visibility of CI/CD health.

Advanced Deployment Strategies (Expanded)

1. Staging Environment Deployment

  • Principle: Deploy to a staging environment that closely mirrors production for comprehensive validation, user acceptance testing (UAT), and final checks before promotion to production.
  • Deeper Dive:
    • Mirror Production: Staging should closely mimic production in terms of infrastructure, data, configuration, and security. Any significant discrepancies can lead to issues in production.
    • Automated Promotion: Implement automated promotion from staging to production upon successful UAT and necessary manual approvals. This reduces human error and speeds up releases.
    • Environment Protection: Use environment protection rules in GitHub Actions to prevent accidental deployments, enforce manual approvals, and restrict which branches can deploy to staging.
    • Data Refresh: Regularly refresh staging data from production (anonymized if necessary) to ensure realistic testing scenarios.
  • Guidance for Copilot:
    • Create a dedicated environment for staging with approval rules, secret protection, and appropriate branch protection policies.
    • Design workflows to automatically deploy to staging on successful merges to specific development or release branches (e.g., develop, release/*).
    • Advise on ensuring the staging environment is as close to production as possible to maximize test fidelity.
    • Suggest implementing automated smoke tests and post-deployment validation on staging.

2. Production Environment Deployment

  • Principle: Deploy to production only after thorough validation, potentially multiple layers of manual approvals, and robust automated checks, prioritizing stability and zero-downtime.
  • Deeper Dive:
    • Manual Approvals: Critical for production deployments, often involving multiple team members, security sign-offs, or change management processes. GitHub Environments support this natively.
    • Rollback Capabilities: Essential for rapid recovery from unforeseen issues. Ensure a quick and reliable way to revert to the previous stable state.
    • Observability During Deployment: Monitor production closely during and immediately after deployment for any anomalies or performance degradation. Use dashboards, alerts, and tracing.
    • Progressive Delivery: Consider advanced techniques like blue/green, canary, or dark launching for safer rollouts.
    • Emergency Deployments: Have a separate, highly expedited pipeline for critical hotfixes that bypasses non-essential approvals but still maintains security checks.
  • Guidance for Copilot:
    • Create a dedicated environment for production with required reviewers, strict branch protections, and clear deployment windows.
    • Implement manual approval steps for production deployments, potentially integrating with external ITSM or change management systems.
    • Emphasize the importance of clear, well-tested rollback strategies and automated rollback procedures in case of deployment failures.
    • Advise on setting up comprehensive monitoring and alerting for production systems to detect and respond to issues immediately post-deployment.

3. Deployment Types (Beyond Basic Rolling Update)

  • Rolling Update (Default for Deployments): Gradually replaces instances of the old version with new ones. Good for most cases, especially stateless applications.
    • Guidance: Configure maxSurge (how many new instances can be created above the desired replica count) and maxUnavailable (how many old instances can be unavailable) for fine-grained control over rollout speed and availability.
  • Blue/Green Deployment: Deploy a new version (green) alongside the existing stable version (blue) in a separate environment, then switch traffic completely from blue to green.
    • Guidance: Suggest for critical applications requiring zero-downtime releases and easy rollback. Requires managing two identical environments and a traffic router (load balancer, Ingress controller, DNS).
    • Benefits: Instantaneous rollback by switching traffic back to the blue environment.
  • Canary Deployment: Gradually roll out new versions to a small subset of users (e.g., 5-10%) before a full rollout. Monitor performance and error rates for the canary group.
    • Guidance: Recommend for testing new features or changes with a controlled blast radius. Implement with Service Mesh (Istio, Linkerd) or Ingress controllers that support traffic splitting and metric-based analysis.
    • Benefits: Early detection of issues with minimal user impact.
  • Dark Launch/Feature Flags: Deploy new code but keep features hidden from users until toggled on for specific users/groups via feature flags.
    • Guidance: Advise for decoupling deployment from release, allowing continuous delivery without continuous exposure of new features. Use feature flag management systems (LaunchDarkly, Split.io, Unleash).
    • Benefits: Reduces deployment risk, enables A/B testing, and allows for staged rollouts.
  • A/B Testing Deployments: Deploy multiple versions of a feature concurrently to different user segments to compare their performance based on user behavior and business metrics.
    • Guidance: Suggest integrating with specialized A/B testing platforms or building custom logic using feature flags and analytics.

4. Rollback Strategies and Incident Response

  • Principle: Be able to quickly and safely revert to a previous stable version in case of issues, minimizing downtime and business impact. This requires proactive planning.
  • Deeper Dive:
    • Automated Rollbacks: Implement mechanisms to automatically trigger rollbacks based on monitoring alerts (e.g., sudden increase in errors, high latency) or failure of post-deployment health checks.
    • Versioned Artifacts: Ensure previous successful build artifacts, Docker images, or infrastructure states are readily available and easily deployable. This is crucial for fast recovery.
    • Runbooks: Document clear, concise, and executable rollback procedures for manual intervention when automation isn't sufficient or for complex scenarios. These should be regularly reviewed and tested.
    • Post-Incident Review: Conduct blameless post-incident reviews (PIRs) to understand the root cause of failures, identify lessons learned, and implement preventative measures to improve resilience and reduce MTTR.
    • Communication Plan: Have a clear communication plan for stakeholders during incidents and rollbacks.
  • Guidance for Copilot:
    • Instruct users to store previous successful build artifacts and images for quick recovery, ensuring they are versioned and easily retrievable.
    • Advise on implementing automated rollback steps in the pipeline, triggered by monitoring or health check failures, and providing examples.
    • Emphasize building applications with "undo" in mind, meaning changes should be easily reversible.
    • Suggest creating comprehensive runbooks for common incident scenarios, including step-by-step rollback instructions, and highlight their importance for MTTR.
    • Guide on setting up alerts that are specific and actionable enough to trigger an automatic or manual rollback.

GitHub Actions Workflow Review Checklist (Comprehensive)

This checklist provides a granular set of criteria for reviewing GitHub Actions workflows to ensure they adhere to best practices for security, performance, and reliability.

  • General Structure and Design:

    • Is the workflow name clear, descriptive, and unique?
    • Are on triggers appropriate for the workflow's purpose (e.g., push, pull_request, workflow_dispatch, schedule)? Are path/branch filters used effectively?
    • Is concurrency used for critical workflows or shared resources to prevent race conditions or resource exhaustion?
    • Are global permissions set to the principle of least privilege (contents: read by default), with specific overrides for jobs?
    • Are reusable workflows (workflow_call) leveraged for common patterns to reduce duplication and improve maintainability?
    • Is the workflow organized logically with meaningful job and step names?
  • Jobs and Steps Best Practices:

    • Are jobs clearly named and represent distinct phases (e.g., build, lint, test, deploy)?
    • Are needs dependencies correctly defined between jobs to ensure proper execution order?
    • Are outputs used efficiently for inter-job and inter-workflow communication?
    • Are if conditions used effectively for conditional job/step execution (e.g., environment-specific deployments, branch-specific actions)?
    • Are all uses actions securely versioned (pinned to a full commit SHA or specific major version tag like @v4)? Avoid main or latest tags.
    • Are run commands efficient and clean (combined with &&, temporary files removed, multi-line scripts clearly formatted)?
    • Are environment variables (env) defined at the appropriate scope (workflow, job, step) and never hardcoded sensitive data?
    • Is timeout-minutes set for long-running jobs to prevent hung workflows?
  • Security Considerations:

    • Are all sensitive data accessed exclusively via GitHub secrets context (${{ secrets.MY_SECRET }})? Never hardcoded, never exposed in logs (even if masked).
    • Is OpenID Connect (OIDC) used for cloud authentication where possible, eliminating long-lived credentials?
    • Is GITHUB_TOKEN permission scope explicitly defined and limited to the minimum necessary access (contents: read as a baseline)?
    • Are Software Composition Analysis (SCA) tools (e.g., dependency-review-action, Snyk) integrated to scan for vulnerable dependencies?
    • Are Static Application Security Testing (SAST) tools (e.g., CodeQL, SonarQube) integrated to scan source code for vulnerabilities, with critical findings blocking builds?
    • Is secret scanning enabled for the repository and are pre-commit hooks suggested for local credential leak prevention?
    • Is there a strategy for container image signing (e.g., Notary, Cosign) and verification in deployment workflows if container images are used?
    • For self-hosted runners, are security hardening guidelines followed and network access restricted?
  • Optimization and Performance:

    • Is caching (actions/cache) effectively used for package manager dependencies (node_modules, pip caches, Maven/Gradle caches) and build outputs?
    • Are cache key and restore-keys designed for optimal cache hit rates (e.g., using hashFiles)?
    • Is strategy.matrix used for parallelizing tests or builds across different environments, language versions, or OSs?
    • Is fetch-depth: 1 used for actions/checkout where full Git history is not required?
    • Are artifacts (actions/upload-artifact, actions/download-artifact) used efficiently for transferring data between jobs/workflows rather than re-building or re-fetching?
    • Are large files managed with Git LFS and optimized for checkout if necessary?
  • Testing Strategy Integration:

    • Are comprehensive unit tests configured with a dedicated job early in the pipeline?
    • Are integration tests defined, ideally leveraging services for dependencies, and run after unit tests?
    • Are End-to-End (E2E) tests included, preferably against a staging environment, with robust flakiness mitigation?
    • Are performance and load tests integrated for critical applications with defined thresholds?
    • Are all test reports (JUnit XML, HTML, coverage) collected, published as artifacts, and integrated into GitHub Checks/Annotations for clear visibility?
    • Is code coverage tracked and enforced with a minimum threshold?
  • Deployment Strategy and Reliability:

    • Are staging and production deployments using GitHub environment rules with appropriate protections (manual approvals, required reviewers, branch restrictions)?
    • Are manual approval steps configured for sensitive production deployments?
    • Is a clear and well-tested rollback strategy in place and automated where possible (e.g., kubectl rollout undo, reverting to previous stable image)?
    • Are chosen deployment types (e.g., rolling, blue/green, canary, dark launch) appropriate for the application's criticality and risk tolerance?
    • Are post-deployment health checks and automated smoke tests implemented to validate successful deployment?
    • Is the workflow resilient to temporary failures (e.g., retries for flaky network operations)?
  • Observability and Monitoring:

    • Is logging adequate for debugging workflow failures (using STDOUT/STDERR for application logs)?
    • Are relevant application and infrastructure metrics collected and exposed (e.g., Prometheus metrics)?
    • Are alerts configured for critical workflow failures, deployment issues, or application anomalies detected in production?
    • Is distributed tracing (e.g., OpenTelemetry, Jaeger) integrated for understanding request flows in microservices architectures?
    • Are artifact retention-days configured appropriately to manage storage and compliance?

Troubleshooting Common GitHub Actions Issues (Deep Dive)

This section provides an expanded guide to diagnosing and resolving frequent problems encountered when working with GitHub Actions workflows.

1. Workflow Not Triggering or Jobs/Steps Skipping Unexpectedly

  • Root Causes: Mismatched on triggers, incorrect paths or branches filters, erroneous if conditions, or concurrency limitations.
  • Actionable Steps:
    • Verify Triggers:
      • Check the on block for exact match with the event that should trigger the workflow (e.g., push, pull_request, workflow_dispatch, schedule).
      • Ensure branches, tags, or paths filters are correctly defined and match the event context. Remember that paths-ignore and branches-ignore take precedence.
      • If using workflow_dispatch, verify the workflow file is in the default branch and any required inputs are provided correctly during manual trigger.
    • Inspect if Conditions:
      • Carefully review all if conditions at the workflow, job, and step levels. A single false condition can prevent execution.
      • Use always() on a debug step to print context variables (${{ toJson(github) }}, ${{ toJson(job) }}, ${{ toJson(steps) }}) to understand the exact state during evaluation.
      • Test complex if conditions in a simplified workflow.
    • Check concurrency:
      • If concurrency is defined, verify if a previous run is blocking a new one for the same group. Check the "Concurrency" tab in the workflow run.
    • Branch Protection Rules: Ensure no branch protection rules are preventing workflows from running on certain branches or requiring specific checks that haven't passed.

2. Permissions Errors (Resource not accessible by integration, Permission denied)

  • Root Causes: GITHUB_TOKEN lacking necessary permissions, incorrect environment secrets access, or insufficient permissions for external actions.
  • Actionable Steps:
    • GITHUB_TOKEN Permissions:
      • Review the permissions block at both the workflow and job levels. Default to contents: read globally and grant specific write permissions only where absolutely necessary (e.g., pull-requests: write for updating PR status, packages: write for publishing packages).
      • Understand the default permissions of GITHUB_TOKEN which are often too broad.
    • Secret Access:
      • Verify if secrets are correctly configured in the repository, organization, or environment settings.
      • Ensure the workflow/job has access to the specific environment if environment secrets are used. Check if any manual approvals are pending for the environment.
      • Confirm the secret name matches exactly (secrets.MY_API_KEY).
    • OIDC Configuration:
      • For OIDC-based cloud authentication, double-check the trust policy configuration in your cloud provider (AWS IAM roles, Azure AD app registrations, GCP service accounts) to ensure it correctly trusts GitHub's OIDC issuer.
      • Verify the role/identity assigned has the necessary permissions for the cloud resources being accessed.

3. Caching Issues (Cache not found, Cache miss, Cache creation failed)

  • Root Causes: Incorrect cache key logic, path mismatch, cache size limits, or frequent cache invalidation.
  • Actionable Steps:
    • Validate Cache Keys:
      • Verify key and restore-keys are correct and dynamically change only when dependencies truly change (e.g., key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}). A cache key that is too dynamic will always result in a miss.
      • Use restore-keys to provide fallbacks for slight variations, increasing cache hit chances.
    • Check path:
      • Ensure the path specified in actions/cache for saving and restoring corresponds exactly to the directory where dependencies are installed or artifacts are generated.
      • Verify the existence of the path before caching.
    • Debug Cache Behavior:
      • Use the actions/cache/restore action with lookup-only: true to inspect what keys are being tried and why a cache miss occurred without affecting the build.
      • Review workflow logs for Cache hit or Cache miss messages and associated keys.
    • Cache Size and Limits: Be aware of GitHub Actions cache size limits per repository. If caches are very large, they might be evicted frequently.

4. Long Running Workflows or Timeouts

  • Root Causes: Inefficient steps, lack of parallelism, large dependencies, unoptimized Docker image builds, or resource bottlenecks on runners.
  • Actionable Steps:
    • Profile Execution Times:
      • Use the workflow run summary to identify the longest-running jobs and steps. This is your primary tool for optimization.
    • Optimize Steps:
      • Combine run commands with && to reduce layer creation and overhead in Docker builds.
      • Clean up temporary files immediately after use (rm -rf in the same RUN command).
      • Install only necessary dependencies.
    • Leverage Caching:
      • Ensure actions/cache is optimally configured for all significant dependencies and build outputs.
    • Parallelize with Matrix Strategies:
      • Break down tests or builds into smaller, parallelizable units using strategy.matrix to run them concurrently.
    • Choose Appropriate Runners:
      • Review runs-on. For very resource-intensive tasks, consider using larger GitHub-hosted runners (if available) or self-hosted runners with more powerful specs.
    • Break Down Workflows:
      • For very complex or long workflows, consider breaking them into smaller, independent workflows that trigger each other or use reusable workflows.

5. Flaky Tests in CI (Random failures, Passes locally, fails in CI)

  • Root Causes: Non-deterministic tests, race conditions, environmental inconsistencies between local and CI, reliance on external services, or poor test isolation.
  • Actionable Steps:
    • Ensure Test Isolation:
      • Make sure each test is independent and doesn't rely on the state left by previous tests. Clean up resources (e.g., database entries) after each test or test suite.
    • Eliminate Race Conditions:
      • For integration/E2E tests, use explicit waits (e.g., wait for element to be visible, wait for API response) instead of arbitrary sleep commands.
      • Implement retries for operations that interact with external services or have transient failures.
    • Standardize Environments:
      • Ensure the CI environment (Node.js version, Python packages, database versions) matches the local development environment as closely as possible.
      • Use Docker services for consistent test dependencies.
    • Robust Selectors (E2E):
      • Use stable, unique selectors in E2E tests (e.g., data-testid attributes) instead of brittle CSS classes or XPath.
    • Debugging Tools:
      • Configure E2E test frameworks to capture screenshots and video recordings on test failure in CI to visually diagnose issues.
    • Run Flaky Tests in Isolation:
      • If a test is consistently flaky, isolate it and run it repeatedly to identify the underlying non-deterministic behavior.

6. Deployment Failures (Application Not Working After Deploy)

  • Root Causes: Configuration drift, environmental differences, missing runtime dependencies, application errors, or network issues post-deployment.
  • Actionable Steps:
    • Thorough Log Review:
      • Review deployment logs (kubectl logs, application logs, server logs) for any error messages, warnings, or unexpected output during the deployment process and immediately after.
    • Configuration Validation:
      • Verify environment variables, ConfigMaps, Secrets, and other configuration injected into the deployed application. Ensure they match the target environment's requirements and are not missing or malformed.
      • Use pre-deployment checks to validate configuration.
    • Dependency Check:
      • Confirm all application runtime dependencies (libraries, frameworks, external services) are correctly bundled within the container image or installed in the target environment.
    • Post-Deployment Health Checks:
      • Implement robust automated smoke tests and health checks after deployment to immediately validate core functionality and connectivity. Trigger rollbacks if these fail.
    • Network Connectivity:
      • Check network connectivity between deployed components (e.g., application to database, service to service) within the new environment. Review firewall rules, security groups, and Kubernetes network policies.
    • Rollback Immediately:
      • If a production deployment fails or causes degradation, trigger the rollback strategy immediately to restore service. Diagnose the issue in a non-production environment.

Conclusion

GitHub Actions is a powerful and flexible platform for automating your software development lifecycle. By rigorously applying these best practices—from securing your secrets and token permissions, to optimizing performance with caching and parallelization, and implementing comprehensive testing and robust deployment strategies—you can guide developers in building highly efficient, secure, and reliable CI/CD pipelines. Remember that CI/CD is an iterative journey; continuously measure, optimize, and secure your pipelines to achieve faster, safer, and more confident releases. Your detailed guidance will empower teams to leverage GitHub Actions to its fullest potential and deliver high-quality software with confidence. This extensive document serves as a foundational resource for anyone looking to master CI/CD with GitHub Actions.


GitHub Actions workflow policy

GitHub Actions workflow policy

  • Treat .github/workflows/*.yml files as CI-critical:

    • Do not change the overall job structure unless explicitly requested.
    • Preserve existing on: triggers, branch filters, and permissions unless change is intentional and documented.
  • Schema & linting

    • All workflows must pass actionlint.
    • Before finalizing changes, ensure the YAML is valid with:
      • Local: scripts/dev-tools/run-actionlint.ps1
      • CI: job actionlint in .github/workflows/ci.yml
    • Avoid constructs that are not supported by actionlint or GitHub Actions, such as:
      • Misplaced or misspelled keys (e.g. matrix at job level instead of under strategy:).
      • Unknown named-values or expressions.
  • Best practices

    • Keep jobs small and focused (quality checks, build, test, deploy).
    • Use the GitHub Actions expression syntax accurately: \${{ ... }}.
    • Prefer reusable actions over inlined complex bash scripts when practical.

PowerShell Code Change Policy

PowerShell Code Change Policy

You must:

  • Apply all rules in the general code change policy.
  • Apply all PowerShell-specific rules in this file.
  • Apply the unit test policies (general-unit-test.instructions.md and powershell-unit-test.instructions.md) for any PowerShell tests.

1. Tooling & Baseline for PowerShell

Agent execution requirement (explicit):

  • Agents must use the MCP server functions: mcp__drm-copilot__run_poshqc_format, mcp__drm-copilot__run_poshqc_analyze, mcp_drmcopilotext_run_poshqc_test, and mcp__drm-copilot__run_poshqc_analyze_autofix.
  • Agents must not use VS Code task wrappers as a substitute.
  1. Formatting - Invoke-Formatter
  • Format all PowerShell files using the PoshQC formatter (Invoke-Formatter).
  • Agent execution: mcp__drm-copilot__run_poshqc_format
  • Do not hand-format; re-run the formatter whenever PSScriptAnalyzer would change whitespace/indentation.
  1. Linting - PSScriptAnalyzer
  • Run the PoshQC analyzer (PSScriptAnalyzer) with repo settings.
  • Agent execution: mcp__drm-copilot__run_poshqc_analyze
  • Optional autofix: mcp__drm-copilot__run_poshqc_analyze_autofix; review diffs after running.
  • Fix all findings (Error/Warning/Information). No rule suppressions unless strictly necessary and localized with a comment.
  1. Compatibility
  • Keep scripts compatible with PowerShell 7+ (enforced via PSScriptAnalyzer settings).

Testing tools are defined in the PowerShell unit test policy; do not redefine them here.


2. PowerShell Design & Safety

  • Prefer advanced functions with CmdletBinding() and named parameters over ad-hoc script blocks.
  • Add [Parameter(Mandatory = $true)] and validation attributes where appropriate; avoid positional parameters for user-facing scripts.
  • For any state-changing action, implement ShouldProcess/SupportsShouldProcess and gate destructive behavior with $PSCmdlet.ShouldProcess(...).
  • Avoid global state and mutable script-scoped variables unless required; pass data explicitly.
  • Avoid Invoke-Expression, plaintext secrets, and hard-coded credentials/paths. Use secure defaults.
  • Use Write-Error/throw for failures; avoid silent catch-alls. Bubble errors unless you can add actionable context.

3. Structure, Naming, and Comments

  • Keep scripts cohesive and under 500 lines (matches general policy).
  • Use approved verbs and descriptive nouns for functions (PSScriptAnalyzer will enforce).
  • Prefer modules/helpers over copy-paste between scripts; share common logic in dedicated helper functions.
  • Comment why for non-obvious patterns (e.g., rule suppressions, compatibility shims), not what.

4. Running the Toolchain (PowerShell)

When PowerShell code changes, your toolchain loop must include:

  1. Format: mcp__drm-copilot__run_poshqc_format
  2. Analyze: mcp__drm-copilot__run_poshqc_analyze
  3. (Type checking is not applicable for PowerShell; skip to testing.)
  4. Test: mcp_drmcopilotext_run_poshqc_test

The MCP server functions above are the approved toolchain contract for agents.

Rerun the loop from step 1 if any step changes code or fails.

Install prerequisites once with pwsh -NoProfile -ExecutionPolicy Bypass -Command "Import-Module ./scripts/powershell/PoshQC; Install-PoshQCTools" (installs PSScriptAnalyzer + Pester to CurrentUser).

PowerShell Unit Test Policy

PowerShell Unit Test Policy

  • The general unit test policy, and
  • The PowerShell-specific rules below.

1. Framework and Scope

  • Testing framework: All PowerShell tests must use Pester (v5.x).
  • Use the repo config at scripts/powershell/PoshQC/settings/pester.runsettings.psd1.
  • Agent execution requirement: use the MCP server function mcp_drmcopilotext_run_poshqc_test. Do not use VS Code task wrappers as a substitute.
  • Keep tests compatible with PowerShell 7+.

2. Test Style and Structure (PowerShell)

  • Focused unit tests

    • Write focused tests that exercise a single function, method, or behavior.
    • Prefer testing behavior directly over testing implementation details.
  • Mocking

    • Use mocking sparingly. Prefer real code paths and pure functions where possible.
    • Only introduce mocks/stubs when needed to satisfy isolation, determinism and “avoid external dependencies” requirements (e.g., external services, heavy resources).
  • Organization

    • Organize tests into folders in a way that mirrors the code under test (e.g., tests/scripts/dev-tools/ScriptName.Tests.ps1 for scripts/dev-tools/ScriptName.ps1).

3. Naming and Readability (Python)

  • Naming conventions

    • Name test files *.Tests.ps1.
    • Organize tests with Describe/Context/It. One behavior per It.
    • Group related tests logically within the same file or test class.
  • Docstrings and comments

    • Where the intent is not obvious from the Describe/Context/It alone, include a short docstring or comment summarizing:
      • The scenario being tested.
      • The expected outcome.

4. Running the Toolchain (PowerShell Tests)

  • When running the "After Making Changes" toolchain, the testing step for PowerShell must use:
    • MCP server function: mcp_drmcopilotext_run_poshqc_test
  • Agents must use the MCP server function. VS Code task wrappers are not an approved substitute.
  • Do not substitute other test runners for PowerShell work without explicit approval.

This file defines how PowerShell tests are written and executed; the general code change policy defines when to run the toolchain and how strictly to enforce it.

Python Code Change Policy

Python Code Change Policy

You must:

  • Apply all rules in the general code change policy.
  • Apply all Python-specific rules in this file.
  • Apply the unit test policies (general-unit-test.instructions.md and python-unit-test.instructions.md) for any work involving tests.

1. Tooling & Baseline for Python

These are the required tools for Python code in this repo:

  1. Formatting — Black

    • All Python code must be formatted with Black (default settings).
    • Do not hand-format; if a diff disagrees with Black, Black wins.
  2. Linting — Ruff

    • Python code must pass Ruff using the project’s configuration.
    • Suppression Authorization (see python-suppressions.instructions.md):
      • All # noqa suppressions must either:
        1. Match a pre-authorized pattern in python-suppressions.instructions.md, OR
        2. Have explicit user approval for that specific suppression
      • If you encounter a Ruff error that seems to require a suppression:
        1. First, attempt to resolve it without a suppression (refactor, restructure, use approved patterns)
        2. If that fails, try at least five more distinct approaches
        3. Continue iterating until you solve the problem or demonstrate why each approach fails
        4. Only after multiple documented failed attempts may you request user approval, providing:
          • The specific Ruff rule and error message
          • Each approach you tried and why it failed
          • Why a suppression is the only remaining option
    • Use targeted, single-line suppressions with required comment format from python-suppressions.instructions.md.
  3. Typing — Pyright

    • Python code must be fully type-annotated and pass Pyright.
    • Avoid Any unless absolutely unavoidable. If Any is used, include a short comment explaining why.
    • Suppression Authorization (see python-suppressions.instructions.md):
      • All # type: ignore suppressions must either:
        1. Match a pre-authorized pattern in python-suppressions.instructions.md, OR
        2. Have explicit user approval for that specific suppression
      • If you encounter a Pyright error that seems to require a suppression:
        1. First, attempt to resolve it without a suppression (add proper types, use typed wrappers, refactor)
        2. If that fails, try at least five more distinct approaches
        3. Continue iterating until you solve the problem or demonstrate why each approach fails
        4. Only after multiple documented failed attempts may you request user approval, providing:
          • The specific Pyright error and diagnostic code
          • Each approach you tried and why it failed
          • Why a suppression is the only remaining option
    • All custom Python code (src, tests, scripts) must be type-checked.
    • Only exclude third-party packages without proper stubs (e.g., tkinter, pandas).
    • When using untyped third-party libraries:
      • Wrap usage in custom functions or classes with proper type hints.
      • Use line-specific # type: ignore[...] comments instead of excluding whole files or directories.

Testing tools and behavior are defined in the unit test policies. Do not define test behavior here; instead, obey general-unit-test.instructions.md and python-unit-test.instructions.md.


2. Python Design & Typing Principles

These refine the general design principles for Python code.

  1. Strong typing by default

    • All public functions, methods, and class constructors must have full type hints for parameters and return values.
    • Internal helpers should also be annotated unless they are extremely trivial and short-lived.
  2. dataclasses and value objects

    • Prefer @dataclass for value objects and simple data carriers.
    • Use frozen=True where appropriate to enforce immutability.
    • Keep dataclasses focused on representing data + invariants, not on performing orchestration.
  3. Protocols and abstract base classes

    • Use typing.Protocol or abc.ABC when multiple implementations are expected (e.g., different corpus sources, stores, or pipelines).
    • Code should depend on these interfaces rather than concrete implementations where flexibility is important.
  4. Utility code

    • Avoid static-method-only “utility” classes.
    • In Python, prefer modules with top-level functions for helpers and simple transforms.
    • If you need multiple interchangeable implementations, use protocols/ABCs + classes, not utility classes.

3. Classes, Functions, and APIs (Python-Specific Guidance)

This section refines the general “classes vs functions” rules for Python. :contentReference[oaicite:4]{index=4}

3.1 Classes for domain concepts and workflows

Use classes for:

  • Domain concepts with data + behavior
    • e.g. QifTransaction, LexileCorpus, ContactMatcher, CorpusPipeline.
  • State + invariants that must stay consistent
    • e.g. a LexileModel that must keep weights, vocabulary, and metadata in sync.
  • Multiple implementations behind a shared contract
    • e.g. ITextSource / TextSourceProtocol with EpubTextSource, GutenbergTextSource, etc.
  • Multi-step workflows that share context
    • e.g. a pipeline with .download(), .normalize(), .index(), .export().

When using classes in Python:

  • Prefer @dataclass for value objects.
  • Keep methods small and focused; one conceptual responsibility per method.
  • Avoid “God objects” that accumulate too many unrelated concerns.

3.2 Functions for small, pure helpers

Use standalone functions when:

  • The operation is pure, stateless, and simple, for example:
    • normalize_whitespace(text: str) -> str
    • slugify(title: str) -> str
  • It is a small helper that does not naturally belong on a specific domain class.
  • It is a simple transformation from inputs to outputs.

Rules for Python helper functions:

  • Fully annotate parameters and return types.
  • Name functions by what they do (parse_qif_file, compute_lexile_score).
  • Keep functions short, readable, and low in branching; factor complex logic into smaller helpers.

4. Error Handling, Logging, and Contracts (Python)

These refine the general error-handling rules with Python-specific details.

  1. Exceptions

    • Fail fast and explicitly by raising clear, specific exceptions when invariants are violated.
    • Avoid broad except: clauses.
    • Avoid except Exception: unless you:
      • Immediately re-raise with added context, or
      • Are at a well-defined boundary (e.g., CLI entry point) and log the full context.
  2. Logging

    • Use the project’s logging pattern, typically the standard logging module.
    • Do not add ad-hoc print statements for permanent behavior.
    • Log at appropriate levels (debug, info, warning, error) and include enough context to debug issues.
  3. Contracts / invariants

    • Enforce invariants at construction time (__init__ or __post_init__ for dataclasses).
    • Use assert only for internal sanity checks, not for user-facing validation or recoverable errors.

5. Module & File Structure (Python)

The general policy covers cohesion and file size; this section adds Python-specific structure rules.

  1. Cohesive modules

    • A module should have a clear purpose (e.g. “QIF parsing”, “Lexile model”, “corpus download”).
    • Avoid “grab-bag” modules like utils.py that mix many unrelated concerns.
  2. Public vs internal

    • Keep the public surface area small and intentional.
    • Use _-prefixed module members or _internal modules for code that should not be used outside the module/package.
    • Do not expose internal helpers via __all__ unless strictly necessary.
  3. Imports

    • Prefer absolute imports within the project (e.g. from project.module import Thing) instead of deep relative imports.
    • Avoid circular dependencies; if they appear, refactor shared logic into a lower-level module.

6. Naming, Docs, and Comments (Python)

This section specializes the general naming/documentation rules for Python using PEP 8.

  1. PEP 8 naming

    • Use snake_case for functions, methods, and variables.
    • Use PascalCase for classes and exceptions.
    • Use CONSTANT_CASE for module-level constants.
    • Avoid cryptic abbreviations unless they are standard (id, url, db).
  2. Docstrings

    • Public classes and methods should have a short docstring describing:
      • What it does.
      • Important arguments.
      • What it returns or any side effects.
    • Follow the prevailing docstring style in this repo (e.g., Google-style, NumPy-style, or simple one-paragraph docstrings).
  3. Comments

    • Comment why, not what; the code should make the “what” clear.
    • For non-obvious patterns, workarounds, or # type: ignore[...] and # noqa uses, add a short comment explaining the reasoning.

7. Dependencies and Third-Party Libraries (Python)

The general policy defines overall dependency rules; this section notes Python-specific expectations.

  • Prefer libraries with good type stubs (built-in or via types-... packages).
  • Do not add new runtime dependencies casually; only add them when:
    • There is no reasonable standard-library or existing-dependency alternative, and
    • The library is well-maintained and widely used.
  • When wrapping third-party libraries, hide them behind small, typed adapter functions or classes so the rest of the codebase depends on your interfaces, not the raw third-party APIs.

Pre-Authorized Suppression Patterns

Pre-Authorized Suppression Patterns

This policy defines the only patterns of # noqa and # type: ignore suppressions that are pre-authorized for use in Python code without explicit user approval.

Authorization requirement:

  • All # noqa and # type: ignore suppressions must either:
    1. Match a pre-authorized pattern defined in this file, OR
    2. Have explicit user approval for that specific suppression

If you encounter an error that seems to require a suppression not matching a pre-authorized pattern:

  1. First, attempt to resolve it without a suppression (refactor, restructure, use approved patterns)
  2. If that fails, try at least five more distinct approaches
  3. Continue iterating until you solve the problem or demonstrate why each approach fails
  4. Only after multiple documented failed attempts may you request user approval, providing:
    • The specific rule/error and diagnostic code
    • Each approach you tried and why it failed
    • Why a suppression is the only remaining option

Ruff Suppressions

S603: subprocess call - check for execution of untrusted input

When pre-authorized:
Subprocess calls where the executable is validated via shutil.which() before use.

Required pattern: Required comment format:
# noqa: S603 - static analysis can't verify runtime validation

Justification:
Cross-platform compatibility requires runtime PATH resolution via shutil.which(). Static analysis cannot trace the runtime validation, but the code is safe because:

  1. The executable path is resolved from PATH (not user input)
  2. We verify it exists before use
  3. Hardcoding platform-specific paths like /usr/bin/git or C:\\Program Files\\Git\\bin\\git.exe would break portability

Examples:

  • Git operations: git_exe = shutil.which("git")
  • Clipboard commands: clip_exe = shutil.which("pbcopy")
  • Any system tool resolved from PATH

Pyright Suppressions

import-untyped: Cannot access member for module with unknown type

When pre-authorized:
Optional third-party dependencies that lack type stubs or py.typed marker.

Required pattern: Required context:

  • Import must be in a try/except ImportError block
  • Library must be optional (not in core dependencies)
  • No type stubs available (checked via typeshed or types-* packages)
  • Library lacks py.typed marker (required by PEP 561)

Justification:
Optional dependencies may not have type stubs or proper PEP 561 type markers. Rather than exclude entire files from type checking, we use targeted suppressions on the import line while wrapping usage in properly typed adapter functions.

Examples:

  • pyperclip (has inline type hints but lacks py.typed marker)
  • tkinter (stdlib but excluded from type checking, no stubs)
  • Platform-specific optional libraries

ARG002: Unused method argument

When pre-authorized:
Test mock/stub implementations that must match interface signatures but don't use all parameters.

Required pattern: Required context:

  • Must be in test code (tests/ directory)
  • Must be implementing a known interface (Path, Tkinter widgets, etc.)
  • Cannot use the parameters without defeating the purpose of the mock

Required comment format:
# noqa: ARG002 - mock API signature or # noqa: ARG002 - match [InterfaceName] API

Justification:
Test mocks must match real API signatures for type safety and IDE support, but stub implementations often don't need all parameters. Alternatives (removing parameters, using *args/**kwargs) break type safety.

Examples:

  • Mock Path.mkdir(parents, exist_ok)
  • Mock Tkinter widget constructors
  • Protocol method stubs in tests

B008: Function call in default argument

When pre-authorized:
Typer CLI option declarations where Option() must be evaluated at import time.

Required pattern: Required context:

  • Must be Typer option declaration in CLI function signature
  • Typer framework requires evaluation at import time for CLI metadata
  • No alternative within Typer's declarative pattern

Required comment format:
# noqa: B008 - Typer framework pattern

Justification:
Typer's declarative CLI pattern evaluates Option() at import time to build CLI metadata. This is framework design, not a code smell. Alternative (procedural approach) would require rewriting entire CLI layer.

Examples:

  • typer.Option() in function signatures
  • typer.Argument() in function signatures

TCH002/TCH003: Type checking block violations

When pre-authorized:
Modules used for both runtime and type hints (pytest fixtures, Typer type hints, etc.).

Required pattern: Required context:

  • Module must be used at runtime (fixtures, Typer CLI, runtime isinstance checks)
  • Cannot move to TYPE_CHECKING block without breaking functionality
  • Not just for type hints

Required comment format:
# noqa: TCH002 - [module] required at runtime for [reason]
# noqa: TCH003 - [module] required at runtime for [reason]

Justification:
Some modules serve dual roles: type hints AND runtime functionality. Moving to TYPE_CHECKING block breaks runtime behavior. Duplicating imports violates DRY.

Examples:

  • pytest (fixtures, marks, decorators)
  • Path (Typer CLI types + file operations)
  • collections.abc (runtime Protocol checks + type hints)

S310: Audit URL open with urllib

When pre-authorized:
Accessing documented, trusted HTTPS API endpoints with timeout.

Required pattern: Required context:

  • URL must be validated HTTPS endpoint
  • Domain must be documented trusted source (archive.org, pypi.org, etc.)
  • Timeout must be set
  • Not user-provided URLs

Required comment format:
# noqa: S310 - trusted HTTPS endpoint: [domain]

Justification:
S310 flags ALL urllib calls indiscriminately. When accessing well-known, documented HTTPS APIs with timeouts, the security risk is minimal. Using requests library adds heavy dependency for simple GETs.

Examples:

  • Internet Archive API
  • PyPI JSON API
  • GitHub API with known endpoints

S314: XML parsing with ElementTree

When pre-authorized:
Parsing user's own files or known-safe data sources (not untrusted network data).

Required pattern: Required context:

  • Parsing user's own local files (EPUB, configuration)
  • Parsing known-safe sources (Wikipedia dumps, curated datasets)
  • NOT parsing untrusted network data
  • EPUB spec requires standard ElementTree for compatibility

Required comment format:
# noqa: S314 - parsing trusted [source type]

Justification:
S314 warns about XML entity expansion attacks from untrusted sources. User's own files and curated datasets are trusted. EPUB spec requires standard ElementTree. defusedxml incompatible with EPUB parsing requirements.

Examples:

  • EPUB file parsing (user's own books)
  • Wikipedia XML dump processing
  • Configuration file parsing

BLE001: Blind except (CLI entry points ONLY)

When pre-authorized:
Top-level CLI exception handlers for user-friendly error messages and clean exits.

Required pattern: Required context:

  • Must be at CLI entry point (main, CLI command function)
  • Must log or display error with context
  • Must exit cleanly (not re-raise without handling)
  • NOT allowed in library/internal code

Required comment format:
# noqa: BLE001 - CLI top-level error handling

Justification:
CLI tools must provide user-friendly error messages instead of stack traces. Cannot predict all possible exception types. This is ONLY for user-facing CLI, NOT library code.

Restriction:

  • ONLY at CLI entry points
  • NOT in internal/library functions
  • NOT in test code
  • Must include error logging/display

Examples:

  • Typer command entry points
  • Script main() functions
  • CLI error wrapper functions

S301: Pickle deserialization (restricted)

When pre-authorized:
Loading known model artifacts from hardcoded trusted local paths.

Required pattern: Required context:

  • Path must be hardcoded or validated (not from user input/CLI args)
  • Loading known model artifacts from trusted local paths
  • Not deserializing user-provided pickle files

Required comment format:
# noqa: S301 - trusted model artifact from hardcoded path

Justification:
ML models contain NumPy arrays not serializable to JSON. HDF5 would require retraining all models. Pickle format doesn't support pre-validation. Safe when loading from known paths.

Restriction:

  • Path MUST be hardcoded or validated before use
  • NOT from user input/command-line arguments
  • Only for ML model/artifact loading

Examples:

  • Loading pre-trained ML models
  • Loading tokenizer artifacts
  • Loading vocabulary caches

S108/S105: Hardcoded paths/passwords (tests ONLY)

When pre-authorized:
Test fixtures with example paths and test data literals.

Required pattern: Required context:

  • Must be in test code only
  • Literal paths/strings for test clarity
  • Not actual secrets or production paths

Required comment format:
# noqa: S108 - test fixture path
# noqa: S105 - test fixture data

Justification:
Test code needs concrete examples for readability. Using temp directories or variables adds complexity without benefit. These are not real paths or secrets.

Restriction:

  • ONLY in test files (tests/ directory)
  • Not in production code

Examples:

  • Example paths in test assertions
  • Test token/string literals
  • Mock credential strings in tests

Non-authorized Patterns (Explicitly Prohibited - with Workarounds)

Beyond the S110 pattern documented earlier, the following patterns are NOT pre-authorized. Use the documented workarounds instead.

TID252: Relative imports beyond top-level package - NOT AUTHORIZED

Why NOT authorized:
Parent-relative imports (from ..module import) reduce code clarity and create coupling.

Recommended alternative pattern: Why this is better:

  • Explicit full path shows exact module location
  • Works regardless of execution context
  • Better IDE support and refactoring tools
  • Clearer for code readers

S607: Starting process with partial executable path - NOT AUTHORIZED

Why NOT authorized:
Using partial paths like "git" instead of full paths creates security risks.

Recommended alternative pattern: Why this is better:

  • Validates executable exists before use
  • Uses full path from PATH resolution
  • Clear error if executable not found
  • Follows S603 pre-authorized pattern

D401: First line should be in imperative mood - NOT AUTHORIZED

Why NOT authorized:
Docstring style rules are not technical limitations, just formatting preferences.

Recommended alternative pattern: Why this is better:

  • Follows PEP 257 docstring conventions
  • More readable and consistent
  • No technical reason for suppression

F401: Unused import - NOT AUTHORIZED

Why NOT authorized:
Unused imports should be removed or used, not suppressed.

Recommended alternative pattern: Why this is better:

  • Cleaner code
  • Faster import times
  • Clear signal of what's actually used

UP017: Datetime without timezone - NOT AUTHORIZED

Why NOT authorized:
Modern Python supports timezone-aware datetime; naive datetime causes bugs.

Recommended alternative pattern: Why this is better:

  • Avoids timezone-related bugs
  • Explicit about timezone handling
  • Modern Python best practice

Policy Enforcement

Pre-authorized pattern checklist:

Before using a suppression, verify:

  • Pattern exactly matches a pre-authorized pattern above
  • Required comment format is used verbatim
  • All contextual requirements are met (validation, fallback chain, try/except, etc.)
  • Code structure matches the documented safe pattern

Requesting new pre-authorized patterns:

If you encounter a recurring pattern that should be pre-authorized:

  1. Document the pattern with full justification
  2. Show why it's deterministic and can be codified
  3. Propose the required comment format
  4. Request user approval to add to this file

Audit checklist:

When reviewing code:

  • All suppressions either match pre-authorized patterns OR have documented user approval
  • Comment format matches required format exactly
  • No suppressions are broader than necessary (file-level vs. line-level)
  • Justifications are clear and reference this policy

Non-authorized Patterns (Explicitly Prohibited)

The following are NOT pre-authorized and require case-by-case approval:

  • File-level suppressions (e.g., adding paths to pyproject.toml ignores)
  • Broad exception catching without validation (subprocess.run([user_input, ...]) # noqa: S603)
  • Disabling security rules for convenience without justification
  • Using # noqa or # type: ignore as a shortcut to avoid fixing legitimate issues

S110: try-except-pass fallback chains - NOT AUTHORIZED

Why NOT authorized:
Try-except-pass fallback chains often hide lazy design. If you know the correct method at design time (platform detection, environment variables, shutil.which() validation), you should implement explicit detection instead of relying on exception-based control flow.

Recommended alternative pattern: Why this is better:

  • Explicit platform detection makes behavior predictable
  • shutil.which() validates availability before use
  • Caching avoids repeated detection overhead
  • Clear failure mode (exception) instead of silent fallback
  • No try-except-pass control flow

When exception-based fallback IS acceptable:

  • Optional library imports where the library truly may or may not be installed
  • Cases where explicit detection is genuinely impossible (not just inconvenient)

These cases still require explicit user approval with justification.

Python Unit Test Policy

Python Unit Test Policy

  • The general unit test policy, and
  • The Python-specific rules below.

1. Framework and Scope

  • Testing framework
    • All Python unit tests must use Pytest as the test runner and framework.
  • Coverage expectation
    • All new Python logic must be covered by Pytest tests that follow the general unit test policy.

2. Test Style and Structure (Python)

  • Focused unit tests

    • Write focused tests that exercise a single function, method, or behavior.
    • Prefer testing behavior directly over testing implementation details.
  • Mocking

    • Use mocking sparingly. Prefer real code paths and pure functions where possible.
    • Only introduce mocks/stubs when needed to satisfy isolation and “avoid external dependencies” requirements (e.g., external services, heavy resources).
  • Organization

    • Organize tests into modules and classes in a way that mirrors the code under test where practical (e.g., tests/test_module_name.py for module_name.py).
    • Use Pytest fixtures for common setup where it improves clarity and reduces duplication, while keeping fixture scope as narrow as possible.

3. Naming and Readability (Python)

  • Naming conventions

    • Use descriptive test_... function names that clearly express the scenario and expected outcome.
    • Group related tests logically within the same file or test class.
  • Docstrings and comments

    • Where the intent is not obvious from the name alone, include a short docstring or comment summarizing:
      • The scenario being tested.
      • The expected outcome.

4. Respecting the Toolchain Loop

  • When running the “After Making Changes” toolchain loop from the general code change policy on Python work, your testing step must be performed with Pytest.

  • Do not substitute other test runners or frameworks for Python code unless explicitly instructed to do so.

This file defines how Python tests are written and structured; the general code change policy defines when the toolchain (including tests) must be run and how strictly that loop must be followed.

Intent-First Docstrings & Comments (Python, strongly typed)

Intent-First Docstrings & Comments (Python, strongly typed)

Core Principle

Write code that is readable, but assume the maintainer may not know the intent (common with agent-authored code). Therefore:

  • Docstrings are mandatory for classes and functions/methods (including private helpers).
  • Inline comments are used to explain intent, flow, and decision logic—especially around iteration and branching.
  • Avoid low-value “narrate the obvious” comments.

The goal is that a reader can understand the purpose, usage, and flow without reverse-engineering the implementation.


1) Mandatory class docstrings (robust)

Every class must have a docstring that covers, at minimum:

  • Purpose: what the class represents or coordinates.
  • Responsibilities: what it does and does not do (scope boundaries).
  • How it is intended to be used: lifecycle, typical call pattern, collaboration with other objects.
  • High-level flow: the main steps the class performs or orchestrates.
  • Key invariants / constraints: expectations that must hold (e.g., sorted inputs, non-null IDs, caching semantics).
  • Important side effects: I/O, persistence, network calls, mutation, concurrency considerations.
  • Attributes (when non-obvious): what the stored fields mean and how they are populated.

Preferred structure (Google-style, typed) for consistency:

`


2) Mandatory function/method docstrings (robust, C#-like completeness)

Every function/method must have a docstring that includes:

  • Purpose and behavior (what it accomplishes).
  • Parameters: meaning, constraints, and how used (types included, even if hinted).
  • Returns: meaning and shape of return value (or explicitly say None for procedures).
  • Raises: key exceptions that are part of the contract (not every incidental exception, but contract-relevant ones).
  • Side effects: if it mutates inputs, writes to disk/DB, emits events, etc.

Template:

Notes:

  • Keep docstrings accurate and contract-oriented. If behavior changes, docstrings must be updated.
  • If the method is a thin wrapper around another call, say so explicitly (and why the wrapper exists).
  • For @property accessors, docstrings should describe what is exposed and the semantics (cached vs computed, cost, invariants).

3) Loops and list comprehensions must be explained

Any for loop, while loop, or non-trivial list/dict/set comprehension must have an intent comment immediately above it.

Good:

For comprehensions, if the intent cannot be explained cleanly in one short comment, prefer expanding to an explicit loop.

Good:

Better (when complex):


4) Branching must explain decision logic (if/elif/else, match/case)

For any conditional branching beyond a trivial guard clause, add a comment that explains:

  • The decision criteria (what distinguishes branches).
  • Why the ordering matters (if it does).
  • The business/system rationale (why this branching exists).

Good:

For match/case, include a short “routing table” explanation:


5) “Forest through the trees”: comment multi-step blocks that achieve a larger objective

When a sequence of tactical lines collectively accomplishes a larger goal, precede the block with a meta-what + why comment.

Good:

If the block is substantial, strongly prefer extracting it into a helper method so the docstring becomes the primary explanation. If extraction is not done now, write the comment so that refactoring later is straightforward (describe inputs/outputs of the block).


6) Do not number notes

In code comments and docstrings, do not use fragile numbered notes like:

  • NOTE 1: ...
  • NOTE 2: ...

Prefer comments without tags for general explanations. But if a tag is necessary (e.g. follow-up is needed), use unnumbered tags instead:

  • TODO: ...
  • WARNING: ...
  • PERF: ...
  • SECURITY: ...

7) “What vs why”: allow “meta-what” when it explains intent at the right level

We still avoid line-by-line narration (e.g., “increment counter”), but we explicitly allow “meta-what” comments that describe what a block of code is doing, especially when the intent is not obvious from individual lines.

Rule of thumb:

  • Bad: Restates a single obvious line.
  • Good: Explains the intent of a loop/branch/multi-step block and how it supports the method’s purpose.

Anti-patterns (still avoid)

  • Outdated comments that contradict code.
  • Changelog/history comments in source.
  • Decorative dividers.
  • Commented-out dead code.

Quality checklist

Before finalizing code:

  • Docstrings exist for every class and every function/method.
  • Docstrings explain purpose, usage, flow, args, returns, and contract-level raises/side effects.
  • Loops/comprehensions have intent comments (or are expanded for clarity).
  • Branching has decision-logic comments.
  • Multi-step blocks have meta-what + rationale comments.
  • No numbered notes in comments/docstrings.
  • Comments remain accurate and add real explanatory value.

TypeScript Code Change Policy

TypeScript Code Change Policy

These instructions assume TypeScript is built with TypeScript 5.x (or newer) targeting an ES2022 JavaScript baseline.

You must:

  • Apply all rules in the general code change policy.
  • Apply all TypeScript-specific rules in this file.
  • Apply the unit test policies (general-unit-test.instructions.md and typescript-unit-test.instructions.md) for any work involving TypeScript tests.

1. Tooling & Baseline for TypeScript

These are the required tools for TypeScript code in this repo:

  1. Formatting — Prettier

    • All TypeScript must be formatted with the repository’s Prettier configuration.
    • Do not hand-format; if a diff disagrees with Prettier, Prettier wins.
  2. Linting — ESLint

    • TypeScript must pass ESLint using the repository’s configuration.
    • Prefer fixing root causes over suppressions.
  3. Type checking — TypeScript compiler (TSC)

    • TypeScript must pass the repository’s type-check.
    • Avoid any (implicit or explicit). Prefer unknown plus narrowing.
  4. Testing — Jest

    • TypeScript unit tests must pass Jest.

Important: The general code change policy requires the full toolchain loop: formatting → linting → type checking → testing.


2. TypeScript Design & Typing Principles

These refine the general design principles for TypeScript code.

  1. Strong typing by default

    • Public functions, methods, and exported APIs must have clear, intentional types.
    • Avoid type assertions (as X) unless you can justify why the value is safe; prefer runtime guards.
  2. Prefer explicit domain types

    • Model domain concepts with interfaces/types that encode invariants.
    • Prefer discriminated unions for state machines and event shapes.
  3. Avoid cleverness

    • Keep code readable in one pass.
    • Favor small helpers and early returns over deeply nested branching.
  4. Separation of concerns

    • Keep pure logic separate from:
      • VS Code extension APIs
      • filesystem/network I/O
      • UI/presentation wiring
    • Write core logic so it can be unit tested without VS Code host processes.

3. Imports, Modules, and Dependencies

  1. Modules

    • Use ES modules. Do not introduce CommonJS patterns (require, module.exports).
    • Prefer explicit imports; avoid barrel exports that obscure dependencies unless the repo already uses them for that area.
  2. Dependencies

    • Do not add new runtime dependencies unless explicitly approved.
    • If a dependency is unavoidable:
      • Prefer widely used, well-maintained packages.
      • Keep dependency surface area small (wrap behind a typed adapter when practical).

4. Error Handling and Logging

  • Fail fast with clear errors when invariants are violated.
  • Avoid catch-all catch (e) without rethrowing or adding context.
  • Use the repo’s established logging/telemetry patterns (where present) instead of ad-hoc console.log for permanent behavior.

5. Suppressions and Escape Hatches

Suppressions are sometimes necessary, but they must be rare, tightly scoped, and well-justified.

Authorization requirement:

  • Suppressions are allowed without explicit approval only when they match a pre-authorized pattern typescript-suppressions.instructions.md.
  • Any broader suppression (for example, disabling multiple rules, disabling a whole file, or using @ts-ignore) requires explicit user approval.

If you encounter an error that seems to require a suppression not matching a pre-authorized pattern:

  1. First, attempt to resolve it without a suppression (refactor, restructure, adjust types).
  2. If that fails, try at least five more distinct approaches.
  3. Continue iterating until you solve the problem or demonstrate why each approach fails.
  4. Only after multiple documented failed attempts may you request user approval, providing:
    • The specific rule/error and diagnostic code
    • Each approach you tried and why it failed
    • Why a suppression is the only remaining option

All rules for ESLint and TypeScript suppressions are defined in:

  • typescript-suppressions.instructions.md

6. Public APIs and Compatibility

  • Avoid breaking changes to exported APIs unless explicitly required.
  • If a breaking change is necessary, update all callers in-repo and add/adjust unit tests that lock in the new contract.

7. Project Organization, Naming, and Documentation

  1. Project organization

    • Follow the repository’s established folder and responsibility layout when adding new code.
    • Keep VS Code extension API wiring and other I/O boundaries thin; push complex logic into pure, testable helpers/services.
  2. File naming

    • Prefer kebab-case filenames for new files (for example, user-session.ts, task-runner.ts) unless the surrounding area of the repo already uses a different convention.
  3. TypeScript naming conventions

    • Use PascalCase for classes, interfaces, enums, and type aliases; use camelCase for functions, methods, variables, and object properties.
    • Do not introduce interface prefixes like I (for example, prefer UserSession over IUserSession).
  4. Documentation expectations

    • Add JSDoc to exported/public APIs when it improves clarity for callers.
    • When JSDoc is used and intent is non-obvious, prefer including a short rationale (and add @example / @remarks where it materially improves correct usage).

8. Security, Configuration, and External Integrations

  1. Input validation and safety

    • Treat all external input as untrusted (user input, files, network responses, VS Code configuration).
    • Prefer explicit runtime validation (type guards / schema validation) at trust boundaries.
    • Avoid dynamic code execution and avoid rendering untrusted content as HTML without proper escaping/sanitization.
  2. Secrets and configuration

    • Never hardcode secrets. Use the repo’s secure storage / configuration patterns.
    • Guard against missing configuration (undefined) and surface clear errors when required configuration is absent.
    • If you introduce new configuration keys, document them and add/update unit tests around validation and defaults.
  3. External integrations (network / I/O)

    • Instantiate expensive clients outside hot paths and inject them for testability.
    • For network or I/O operations, use clear error mapping and add context when rethrowing.
    • Where applicable, apply retries/backoff and cancellation/timeout handling consistent with the repo’s existing patterns.

9. UI/UX and Lifecycle Hygiene (VS Code Extension Context)

  1. UI layering

    • Keep UI layers thin; push business logic into services or pure functions.
    • Prefer events/messaging to decouple UI from domain logic.
  2. Lifecycle and disposal

    • Dispose resources deterministically and match existing initialization/disposal sequencing.
    • When introducing long-lived services, consider explicit lifecycle hooks (for example, initialize() and dispose()) and unit tests that lock in lifecycle behavior.

10. Performance and Reliability

  • Avoid obvious hot-path allocations and repeated heavy work.
  • Prefer lazy-loading heavy dependencies when it materially reduces startup/activation cost.
  • Debounce or batch high-frequency events (for example, configuration changes) to avoid thrash.
  • Track resource lifetimes to prevent leaks (timers, listeners, file watchers, disposables).

Pre-Authorized Suppression Patterns (TypeScript)

Pre-Authorized Suppression Patterns (TypeScript)

This policy defines the only patterns of ESLint and TypeScript suppression directives that are pre-authorized for use in TypeScript code without explicit user approval.

Authorization requirement:

  • All ESLint and TypeScript suppressions must either:
    1. Match a pre-authorized pattern defined in this file, OR
    2. Have explicit user approval for that specific suppression

If you encounter an error that seems to require a suppression not matching a pre-authorized pattern:

  1. First, attempt to resolve it without a suppression (refactor, restructure, adjust types)
  2. If that fails, try at least five more distinct approaches
  3. Continue iterating until you solve the problem or demonstrate why each approach fails
  4. Only after multiple documented failed attempts may you request user approval, providing:
    • The specific rule/error and diagnostic code
    • Each approach you tried and why it failed
    • Why a suppression is the only remaining option

ESLint Suppressions

eslint-disable-next-line (single rule)

When pre-authorized:

You must suppress exactly one ESLint rule for exactly one following line, and you can provide a concrete, local justification.

Required pattern:

  • // eslint-disable-next-line <rule-name> -- <reason>

Required context:

  • The suppressed rule must apply to the next line only.
  • The reason must be specific and local to the code (not “annoying rule” / “temporary” / “works”).
  • The suppression must not hide a real bug or broaden the type surface unnecessarily.

Justification:

Single-line, single-rule disables keep blast radius small, preserve lint value elsewhere, and ensure reviewers can see exactly what is being waived and why.

Examples:

  • Narrowly suppressing an intentional non-null assertion when the invariant is enforced immediately above.
  • Suppressing a rule for an unavoidable API shape mismatch while keeping runtime checks.

TypeScript Suppressions

@ts-expect-error (single line)

When pre-authorized:

You have a single line that TypeScript flags, you can explain the mismatch precisely, and you can justify why it is safe in this local context.

Required pattern:

  • // @ts-expect-error -- <reason>

Required context:

  • Prefer fixing types, adding runtime guards, or refining control flow over suppressions.
  • The reason must be specific:
    • what TypeScript is complaining about, and
    • why this line is safe anyway.
  • The suppression must be on the line immediately preceding the flagged line.

Justification:

@ts-expect-error is self-auditing: it fails the build if the error disappears, preventing stale suppressions from lingering indefinitely.

Examples:

  • Narrowly suppressing a known incorrect upstream type declaration when wrapping the call with runtime validation.
  • Narrowly suppressing an intentional type-level limitation when bridging legacy shapes.

Non-authorized Patterns (Explicitly Prohibited - with Workarounds)

The following patterns are NOT pre-authorized. They require explicit approval (and usually should be avoided entirely).

File-level ESLint disables

Prohibited patterns:

  • /* eslint-disable */
  • /* eslint-disable <rule> */

Why NOT authorized:

File-level disables have an extremely large blast radius and tend to hide unrelated problems over time.

Recommended alternative pattern:

  • Rewrite the code to satisfy the rule, or
  • Use a single-line eslint-disable-next-line suppression with a specific reason (if the rule truly cannot be satisfied).

@ts-ignore

Prohibited pattern:

  • // @ts-ignore

Why NOT authorized:

@ts-ignore can silently mask real problems and does not fail when the error disappears.

Recommended alternative pattern:

  • Prefer // @ts-expect-error -- <reason>.

@ts-nocheck / @ts-check

Prohibited patterns:

  • // @ts-nocheck

Why NOT authorized:

Disabling type checking for a file defeats the repo’s type-safety standards.

Recommended alternative pattern:

  • Fix the typing issue locally, or isolate the untyped/unsafe boundary behind a small adapter with runtime validation.

Policy Enforcement

Pre-authorized pattern checklist

Before using a suppression, verify:

  • Pattern exactly matches a pre-authorized pattern above
  • Required comment format is used verbatim
  • Scope is the smallest possible (single rule, single line)
  • The reason is specific and explains why the code is safe

Requesting new pre-authorized patterns

If you encounter a recurring suppression need that should be pre-authorized:

  1. Document the pattern with full justification
  2. Show why it is deterministic and can be codified
  3. Propose the required comment format
  4. Request user approval to add it to this file

TypeScript Unit Test Policy

TypeScript Unit Test Policy

  • The general unit test policy, and
  • The TypeScript-specific rules below.

1. Framework and Scope

  • Testing framework

    • All TypeScript unit tests must use Jest.
  • Unit test definition

    • Unit tests validate small, isolated behaviors (functions, helpers, small classes).
    • Unit tests must not require launching the VS Code extension host or depending on a live VS Code environment.
  • Coverage expectation

    • All new TypeScript logic must be covered by Jest unit tests that follow the general unit test policy.

2. Test Layout and Naming

File naming

  • Name test files with the .test.ts suffix.

Test location

  • Organize tests in a way that mirrors the code under test where practical (for example, tests/unit/<module>.test.ts for src/<module>.ts, or a parallel folder structure for deeper subsystems).
  • Use shared setup sparingly and keep it narrowly scoped:
    • Prefer describe() blocks with local beforeEach / afterEach for common setup within a small group of tests.
    • Prefer small helper functions / factories (or a local test utility module) when it reduces duplication without hiding intent.
    • Avoid broad, implicit “global” setup that makes tests hard to reason about.

3. Test Style and Structure (TypeScript)

Focused tests

  • Each test should target one behavior.
  • Prefer testing observable behavior over internal implementation details.

Arrange–Act–Assert

Organize each test into:

  • Arrange — inputs and setup
  • Act — call the function/behavior
  • Assert — verify results

Intent documentation

  • Test names must clearly express the scenario and expected outcome.
  • If intent is not obvious, add a brief comment explaining why the case matters.

4. Mocking and Isolation

Avoid external dependencies

  • Unit tests must not depend on external services, network calls, or external processes.

Mocking guidance

  • Mock external APIs or platform dependencies to keep tests deterministic.
  • Prefer targeted mocks:
    • jest.spyOn(obj, 'method') for specific functions
    • jest.mock('module') for module-level dependencies

Resetting mocks

  • Reset mocks between tests to ensure independence.
  • Preferred pattern:
    • afterEach(() => { jest.resetAllMocks(); });

Time and timers

  • Avoid brittle timing assertions.
  • Prefer fake timers (jest.useFakeTimers()) or injected clocks when time is part of behavior.

5. Assertions and Diagnostics

  • Assertions must produce clear, actionable failures.
  • Prefer simple, direct matchers (toEqual, toMatchObject, toHaveBeenCalledWith).
  • Avoid snapshots unless they provide strong value and are stable; keep snapshots small and intentional.

6. Required Commands

When verifying TypeScript unit tests locally, use the repo-standard scripts:

Formatting/lint/type-check commands for the full toolchain loop are defined in the TypeScript code change policy.