diff --git a/.github/.bootstrap-ignore b/.github/.bootstrap-ignore deleted file mode 100644 index dcf9e40..0000000 --- a/.github/.bootstrap-ignore +++ /dev/null @@ -1,11 +0,0 @@ -# Purpose: Optional exclude patterns for bootstrap-copilot-config.sh -# Add one rsync exclude pattern per line. - -# Example: -# workflows/ -# dependabot.yml -README.md -agents/README.md -templates/ -scripts/bootstrap-copilot-config.sh -tech-ai-requirements-dev.txt diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 0cae94f..3d581cd 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -6,6 +6,14 @@ Use this format for new updates: - One bullet per meaningful change. - Include file/path scope when useful. +## 2026-04-12 +- Renamed the workflow skill from `internal-cicd-workflow` to `internal-github-actions`, renamed `internal-github-composite-action` to `internal-github-action-composite`, and realigned the GitHub Actions instructions so the umbrella instruction is the family baseline while the composite instruction now carries only composite-specific delta guidance. +- Added a retained-learning governance contract: root `AGENTS.md` now defines repository-root `LESSONS.md` as a non-canonical ledger for durable lessons learned during completed tasks, `.github/copilot-instructions.md` projects the same behavior into native Copilot flows, `INTERNAL_CONTRACT.md` source-governs the invariant, and the new `LESSONS.md` file records retained lessons with canonical-owner pointers. +- Slimmed the retained-learning section in root `AGENTS.md` so the bridge keeps only strategic ownership and boundary language while `.github/copilot-instructions.md` remains the detailed operational projection. +- Expanded the retained-learning contract so `LESSONS.md` may also keep durable corrections to repeated or consequential misapplication of already-codified repository rules, then recorded the bridge-vs-projection lesson for `AGENTS.md` and `.github/copilot-instructions.md`. +- Restructured `LESSONS.md` into two tables so new or still-pending lessons stay separate from codified rules. +- Simplified `LESSONS.md` again so it now keeps only pending lessons; once a lesson is codified into a canonical owner, it is removed from the ledger instead of being duplicated there. + ## 2026-04-11 - Tightened the Python skill split instead of collapsing it: clarified the shared baseline in `.github/instructions/internal-python.instructions.md`, sharpened `internal-project-python` around structured package and application boundaries, and expanded `internal-script-python` plus its layout reference to cover the repository-aligned toolkit pattern used under `.github/scripts/` with shared `lib/`, hash-locked `requirements.txt`, shared `run.sh`, root-level tests, and thin wrapper entrypoints. - Renamed the sync engine skill from `.github/skills/internal-sync-global-copilot-configs-into-repo/` to `.github/skills/internal-agent-sync-global-copilot-configs-into-repo/`, then realigned the paired agent contract and skill invocation metadata to the new canonical skill name. diff --git a/.github/DEPRECATION.md b/.github/DEPRECATION.md index 01f45fe..e065bf0 100644 --- a/.github/DEPRECATION.md +++ b/.github/DEPRECATION.md @@ -1,7 +1,7 @@ # Deprecation Policy ## Purpose -Define a predictable process for deprecating Copilot customization assets (`instructions`, `prompts`, `skills`, `agents`, and templates). +Define a predictable process for deprecating Copilot customization assets (`instructions`, `skills`, `agents`, and templates). ## Lifecycle states - Active: recommended for current use. @@ -16,7 +16,6 @@ Define a predictable process for deprecating Copilot customization assets (`inst 5. Remove only after the window ends and no blocking consumers remain. ## Backward compatibility rules -- Prompts: avoid renaming/removing slash commands without replacement mapping. - Instructions: avoid changing mandatory behavior without documenting impact. - Skills: keep old skill path available during transition. - Agents: keep objective and restriction semantics stable where possible. diff --git a/.github/INVENTORY.md b/.github/INVENTORY.md index 433d028..d8a9f72 100644 --- a/.github/INVENTORY.md +++ b/.github/INVENTORY.md @@ -22,10 +22,6 @@ This file is the exact path inventory for the live GitHub Copilot catalog in thi - `.github/instructions/internal-terraform.instructions.md` - `.github/instructions/internal-yaml.instructions.md` -## Prompts - -No prompt files currently ship in the live catalog. - ## Skills - `.github/skills/antigravity-api-design-principles/SKILL.md` @@ -61,10 +57,9 @@ No prompt files currently ship in the live catalog. - `.github/skills/internal-azure-strategic/SKILL.md` - `.github/skills/internal-change-impact-analysis/SKILL.md` - `.github/skills/internal-changelog-automation/SKILL.md` -- `.github/skills/internal-cicd-workflow/SKILL.md` +- `.github/skills/internal-github-actions/SKILL.md` - `.github/skills/internal-cloud-policy/SKILL.md` - `.github/skills/internal-code-review/SKILL.md` -- `.github/skills/internal-composite-action/SKILL.md` - `.github/skills/internal-copilot-audit/SKILL.md` - `.github/skills/internal-copilot-docs-research/SKILL.md` - `.github/skills/internal-copilot-instructions-creator/SKILL.md` @@ -75,6 +70,7 @@ No prompt files currently ship in the live catalog. - `.github/skills/internal-gcp-operations/SKILL.md` - `.github/skills/internal-gcp-organization-structure/SKILL.md` - `.github/skills/internal-gcp-strategic/SKILL.md` +- `.github/skills/internal-github-action-composite/SKILL.md` - `.github/skills/internal-github-governance/SKILL.md` - `.github/skills/internal-github-operations/SKILL.md` - `.github/skills/internal-github-strategic/SKILL.md` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 289b964..8fd63cc 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ - + ## Description @@ -11,7 +11,6 @@ - [ ] Agent update - [ ] Instruction update -- [ ] Prompt update - [ ] Skill update - [ ] Workflow/automation update - [ ] Verification/automation update diff --git a/.github/README.md b/.github/README.md index dd9b8f9..6113658 100644 --- a/.github/README.md +++ b/.github/README.md @@ -3,14 +3,13 @@ This directory is the source-side catalog for reusable GitHub Copilot customization assets maintained in `cloud-strategy.github`. - `.github/copilot-instructions.md` is the primary detailed policy layer. -- Root [`AGENTS.md`](../AGENTS.md) is the thin bridge for routing, naming, discovery, and the pointer to exact path inventory. +- Root [`AGENTS.md`](../AGENTS.md) is the strategic entrypoint, precedence anchor, and bridge for routing, naming, discovery, and the pointer to exact path inventory. - [`INVENTORY.md`](INVENTORY.md) is the exact path inventory for the live catalog. - This README is an orientation guide for maintainers of the source catalog. It should describe the live on-disk catalog only. ## Live Catalog Summary - Instructions: 17 total (`13 internal-*`, `4 awesome-copilot-*`) -- Prompts: 0 total - Skills: 85 total (`45 internal-*`, `14 obra-*`, `9 awesome-copilot-*`, `8 antigravity-*`, `7 openai-*`, `2 terraform-*`) - Agents: 7 total (`7 internal-*`) - Scripts: 21 tracked files @@ -23,7 +22,7 @@ This directory is the source-side catalog for reusable GitHub Copilot customizat | Path | Purpose | | --- | --- | | `copilot-instructions.md` | Primary detailed policy, validation baseline, routing model, and completion-report contract. | -| `INVENTORY.md` | Exact path inventory for live instructions, prompts, skills, and agents. | +| `INVENTORY.md` | Exact path inventory for live instructions, skills, and agents. | | `copilot-code-review-instructions.md` | Review-specific severity and defect-first guidance. | | `copilot-commit-message-instructions.md` | Commit message conventions. | | `security-baseline.md` | Cross-cutting security bar for workflows and infrastructure changes. | @@ -32,8 +31,6 @@ This directory is the source-side catalog for reusable GitHub Copilot customizat | `CHANGELOG.md` | Source-side history of meaningful catalog changes. | | `PULL_REQUEST_TEMPLATE.md` | PR section order for this repository. | | `dependabot.yml` | Dependency update configuration for this source repository. | -| `obra-superpowers-source-of-truth.json` | Pinned upstream mapping contract for imported `obra-*` skills. | -| `.bootstrap-ignore` | Legacy compatibility artifact retained outside the primary sync workflow. | ### Instructions (`instructions/`) @@ -42,13 +39,7 @@ Instructions are path-driven and auto-apply via `applyTo`. - Repository-owned `internal-*` instructions: `internal-bash`, `internal-docker`, `internal-github-action-composite`, `internal-github-actions`, `internal-java`, `internal-json`, `internal-lambda`, `internal-makefile`, `internal-markdown`, `internal-nodejs`, `internal-python`, `internal-terraform`, `internal-yaml` - Imported `awesome-copilot-*` instructions: `awesome-copilot-azure-devops-pipelines`, `awesome-copilot-go`, `awesome-copilot-kubernetes-manifests`, `awesome-copilot-shell` -Use instructions as automatic file-path guidance. Do not hardcode instruction references into prompts when `applyTo` already resolves the behavior. - -### Prompts (`prompts/`) - -No prompt files currently ship in the live catalog. - -If prompt assets are reintroduced, they must stay aligned with real files under `instructions/`, `skills/`, and `scripts/`. +Use instructions as automatic file-path guidance. Do not restate path-driven behavior in skills when `applyTo` already resolves it. ### Skills (`skills/`) @@ -65,8 +56,8 @@ Skills are grouped into three functional lanes plus imported support families. Some skill directories include support material beyond `SKILL.md`. Current live examples include: - provider families with bundled references and UI metadata: `internal-aws-*`, `internal-azure-*`, `internal-gcp-*`, `internal-github-*` -- repository-owned support bundles such as `internal-agent-*`, `internal-change-impact-analysis`, `internal-cicd-workflow`, `internal-cloud-policy`, `internal-code-review`, `internal-composite-action`, `internal-copilot-*`, `internal-ddd`, `internal-docker`, `internal-kubernetes`, `internal-kubernetes-deployment`, `internal-oop-design-patterns`, `internal-performance-optimization`, `internal-pr-editor`, `internal-project-*`, `internal-script-*`, `internal-spring-boot-development`, `internal-sync-*`, and `internal-terraform` -- workflow packs with bundled references or helpers such as `obra-brainstorming`, `obra-requesting-code-review`, `obra-subagent-driven-development`, `obra-systematic-debugging`, `obra-test-driven-development`, `obra-using-superpowers`, `obra-writing-plans`, and `obra-writing-skills` +- repository-owned support bundles such as `internal-agent-*`, `internal-change-impact-analysis`, `internal-github-actions`, `internal-cloud-policy`, `internal-code-review`, `internal-github-action-composite`, `internal-copilot-*`, `internal-ddd`, `internal-docker`, `internal-kubernetes`, `internal-kubernetes-deployment`, `internal-oop-design-patterns`, `internal-performance-optimization`, `internal-pr-editor`, `internal-project-*`, `internal-script-*`, `internal-spring-boot-development`, `internal-sync-*`, and `internal-terraform` +- workflow packs with bundled references or helpers such as `obra-brainstorming`, `obra-requesting-code-review`, `obra-subagent-driven-development`, `obra-systematic-debugging`, `obra-test-driven-development`, `obra-using-superpowers`, and `obra-writing-plans` - imported or upstream-derived bundles such as `awesome-copilot-agentic-eval`, `awesome-copilot-azure-devops-cli`, `awesome-copilot-azure-pricing`, `awesome-copilot-azure-role-selector`, `awesome-copilot-cloud-design-patterns`, `openai-docx`, `openai-gh-address-comments`, `openai-gh-fix-ci`, `openai-pdf`, `openai-skill-creator`, `openai-slides`, `openai-spreadsheet`, `terraform-terraform-search-import`, and `terraform-terraform-test` Use [`INVENTORY.md`](INVENTORY.md) for the exact path inventory. Use root [`AGENTS.md`](../AGENTS.md) for bridge-level routing and discovery. Use this README for family-level orientation only. @@ -105,7 +96,7 @@ The matching `.py` entrypoints and `scripts/lib/*.py` modules are part of the sa - Trust real on-disk paths and [`INVENTORY.md`](INVENTORY.md) over remembered historical names. Use root [`AGENTS.md`](../AGENTS.md) for bridge-level routing and discovery. - Keep `.github/copilot-instructions.md` as the normative policy layer and update it before root `AGENTS.md` when both must change. - Treat this README as maintainer-facing orientation, not as the normative contract. -- Historical documents such as `../COPILOT_REVIEW.md` and older changelog entries may intentionally mention removed legacy assets. Do not use them as live catalog references. +- Historical documents and older changelog entries may intentionally mention removed legacy assets. Do not use them as live catalog references. ## Maintenance Workflow @@ -133,11 +124,6 @@ Completed operations must end with a concise recap. - Include this section only when instructions were used. - State which instructions were used and why they mattered. -### 📝 Prompts - -- Include this section only when prompts were used. -- State which prompts were used and why they were relevant. - ### 🧩 Skills - Include this section only when skills were used. diff --git a/.github/agents/README.md b/.github/agents/README.md index e3750a1..9bec5ed 100644 --- a/.github/agents/README.md +++ b/.github/agents/README.md @@ -6,14 +6,14 @@ This folder contains deliberate custom agents for repository-owned operational r 1. Apply repository non-negotiables from `copilot-instructions.md`. 2. Apply explicit user request and selected agent behavior (agent-first). 3. Apply matching `instructions/*.instructions.md` (`applyTo` by path). -4. Apply prompt and referenced skill details. +4. Apply referenced skill details. ## Recommended routing - Default operational front door: `internal-router` (routes only; it does not edit files or implement changes). - Direct canonical owners: `internal-fast-executor`, `internal-planning-leader`, `internal-review-guard`, `internal-critical-challenger`. - Source-side catalog sync, rationalization, overlap cleanup, and governance drift correction in this repository: `internal-sync-control-center`. - Cross-repository baseline propagation: `internal-sync-global-copilot-configs-into-repo`. -- PR-focused work should use the `internal-pr-editor` prompt and skill because this repository does not currently ship a dedicated PR editor agent. +- PR-focused work should use the `internal-pr-editor` skill because this repository does not currently ship a dedicated PR editor agent. ## Repo-only agents (not synced to consumers) - `internal-sync-control-center` @@ -25,7 +25,7 @@ This folder contains deliberate custom agents for repository-owned operational r - Keep the operational front door explicit, keep the four canonical owners non-overlapping, and keep reusable logic in skills instead of bloating agent bodies. - Keep downstream owner selection in `internal-router` only; canonical owners define boundaries and recommend a better owner instead of handing off automatically unless a scoped contract explicitly allows invoking `internal-router` as a second parallel lane. - Technology is resolved from file paths and prompt inputs (for example, `**/*.py` -> Python instructions). -- Prefer prompts and skills for detailed task procedures unless a dedicated agent file is present. +- Prefer skills for detailed task procedures unless a dedicated agent file is present. ## Selection guide 1. Use `internal-router` when the user has not yet chosen the right owner or the request could plausibly be execution, planning, review, or challenge. Treat it as dispatch-only. @@ -35,4 +35,4 @@ This folder contains deliberate custom agents for repository-owned operational r 5. Use `internal-critical-challenger` for pre-mortems, objection-first pressure tests, lateral reframing, and failure-mode analysis. 6. Use `internal-sync-control-center` when governing the live `.github/` catalog in this repository: refresh approved external assets, align naming, consolidate overlap, retire obsolete entries, and clean up downstream governance references. Unless the user explicitly asks for an audit or plan first, treat `sync` as a full apply request. 7. Use `internal-sync-global-copilot-configs-into-repo` when aligning a consumer repository with the managed Copilot baseline from this standards repository. -8. Use prompts and skills from `.github/prompts/` and `.github/skills/` for work that does not need a dedicated agent file. +8. Use skills from `.github/skills/` for work that does not need a dedicated agent file. diff --git a/.github/agents/internal-critical-challenger.agent.md b/.github/agents/internal-critical-challenger.agent.md index 4328134..ac409a2 100644 --- a/.github/agents/internal-critical-challenger.agent.md +++ b/.github/agents/internal-critical-challenger.agent.md @@ -23,7 +23,7 @@ You are the repository-owned pressure-test and reframing lane for reasoning, ass ## Core Rules - Challenge one proposal, decision, or assumption set at a time. -- Do not edit files, implement changes, or provide solutions through this route. The value is in the pressure, not in the fix. +- Do not edit files, implement changes, or provide solutions through this route. The value is in the pressure, not in the fix, and the `edit` tool is granted only for saving retained analysis artifacts when needed. - The only write owned by this lane is saving the current challenge analysis as a retained artifact when the user asks for it or when a lane change would otherwise discard it. - The only subagent this lane may invoke is `internal-router`, and only when the user explicitly wants a second parallel operational lane without abandoning the challenge lane. - Do not assume the user's expertise level, intent quality, or context maturity without evidence in the conversation. diff --git a/.github/agents/internal-planning-leader.agent.md b/.github/agents/internal-planning-leader.agent.md index 8e2b813..693875f 100644 --- a/.github/agents/internal-planning-leader.agent.md +++ b/.github/agents/internal-planning-leader.agent.md @@ -29,7 +29,7 @@ You are the planning, authoring, and decision owner for non-trivial operational ## Core Rules - Make assumptions, tradeoffs, and the selected direction explicit. -- Own non-trivial repository-owned authoring for agents, skills, prompts, instructions, routing, and governance updates. +- Own non-trivial repository-owned authoring for agents, skills, instructions, routing, and governance updates. - Do not default into implementation once the design is settled; recommend the right next owner instead. - If this agent is entered by router handoff, use the supplied routing package as input and avoid re-running front-door classification unless the boundary clearly breaks. diff --git a/.github/agents/internal-sync-control-center.agent.md b/.github/agents/internal-sync-control-center.agent.md index bf4cdee..9dd02b6 100644 --- a/.github/agents/internal-sync-control-center.agent.md +++ b/.github/agents/internal-sync-control-center.agent.md @@ -2,6 +2,7 @@ name: internal-sync-control-center description: Use this agent when governing or synchronizing the Copilot customization catalog in this repository. Keep root governance canonical in `AGENTS.md` and `.github/copilot-instructions.md`, keep sync-specific scope and managed external resources here, remove obsolete overlap instead of keeping fallbacks, and align downstream governance after catalog changes. tools: ["read", "edit", "search", "execute", "web", "agent"] +agents: [] --- # Internal Sync Control Center @@ -43,7 +44,7 @@ Treat `.github/skills/internal-agent-sync-control-center/SKILL.md` as the mandat - Do not preserve fallback assets, compatibility aliases, or deprecated variants unless `AGENTS.md` explicitly requires them. - Do not introduce new prefixes, naming schemes, or external asset families unless the user explicitly expands scope. - When a managed `openai/skills` asset is declared below, install or refresh only the mapped skills into `.github/skills/` using the required `openai-` prefix. Do not keep unprefixed copies or add sibling OpenAI skills unless the user explicitly expands scope. -- Do not leave stale references in `AGENTS.md`, prompts, skills, agents, instructions, or scripts after catalog changes. Update README-based catalogs only when README edits are explicitly in scope. +- Do not leave stale references in `AGENTS.md`, skills, agents, instructions, or scripts after catalog changes. Update README-based catalogs only when README edits are explicitly in scope. - Keep agents cohesive around routing and orchestration. Move reusable procedures into skills. - Do not route cross-repository baseline propagation through this agent. Use `internal-sync-global-copilot-configs-into-repo` for consumer-repository alignment. - When the intended managed scope changes, update this file so the policy remains self-consistent over time. diff --git a/.github/agents/internal-sync-global-copilot-configs-into-repo.agent.md b/.github/agents/internal-sync-global-copilot-configs-into-repo.agent.md index d362931..7e58f93 100644 --- a/.github/agents/internal-sync-global-copilot-configs-into-repo.agent.md +++ b/.github/agents/internal-sync-global-copilot-configs-into-repo.agent.md @@ -1,7 +1,8 @@ --- name: internal-sync-global-copilot-configs-into-repo -description: Use this agent when aligning a consumer repository to the managed GitHub Copilot baseline from this standards repository. Keep the paired sync skill as the reusable sync-procedure owner, preserve target `local-*` extensions, and keep root-guidance files aligned to their separate ownership layers. +description: Use this agent when aligning a consumer repository to the managed GitHub Copilot baseline from this standards repository. Keep the paired sync skill as the reusable sync-procedure owner, preserve target `local-*` extensions plus any `.github/local-copilot-overrides.md` layer, and keep root-guidance files aligned to their separate ownership layers. tools: ["read", "edit", "search", "execute", "web", "agent"] +agents: [] --- # Internal Sync Global Copilot Configs Into Repo @@ -40,21 +41,21 @@ Treat this agent plus `.github/skills/internal-agent-sync-global-copilot-configs - Treat this repository as the source of truth for the managed sync baseline. - Start in `plan` by default. Move to `apply` only on explicit request and only when the plan is conflict-safe. - Keep target assumptions narrow and let the paired skill own the mirrored-scope and plan-file details. -- Preserve target `local-*` assets, exclude repository-owned `internal-sync-*` resources from mirroring, and keep root-guidance files layered according to the paired skill contract. +- Preserve target `local-*` assets plus any consumer-owned `.github/local-copilot-overrides.md` file, exclude repository-owned `internal-sync-*` resources from mirroring, and keep root-guidance files layered according to the paired skill contract. - Sync GitHub Copilot assets only unless the user explicitly expands scope. - Do not restate reusable sync procedure in this agent; when the contract drifts, update the paired skill first and then realign this agent. ## Routing - Use this agent for consumer-repository baseline propagation, drift assessment, `plan`, and `apply` runs. -- Use this agent when the target must inherit the current bridge model around `AGENTS.md`, `.github/copilot-instructions.md`, and `.github/INVENTORY.md`. +- Use this agent when the target must inherit the current bridge model around `AGENTS.md`, `.github/copilot-instructions.md`, `.github/local-copilot-overrides.md`, and `.github/INVENTORY.md`. - Do not use this agent for source-side catalog redesign, agent or skill authoring, or governance restructuring in this repository; recommend `internal-planning-leader` instead. - Do not use this agent for routine local execution once the sync contract is already settled and only a small target-local edit remains; recommend the appropriate executor for that repository instead. - When current platform behavior is the deciding factor, validate it through `internal-copilot-docs-research` before changing the sync policy. ## Execution Workflow -1. Confirm the mode: `plan`, `apply`, or source or target drift review. +1. Confirm the mode: `plan`, `apply`, or `audit`. 2. Load the mandatory sync skill and let it own the analyze, planning, apply, plan-file, and validation procedure. 3. Keep boundary and approval decisions in this agent, then report the result using the paired skill contract. @@ -62,7 +63,7 @@ Treat this agent plus `.github/skills/internal-agent-sync-global-copilot-configs - Target analysis and selected mode - Root-guidance alignment strategy -- Preserved `local-*` assets and target-only cleanup decisions +- Preserved `local-*` assets, `.github/local-copilot-overrides.md` status, and target-only cleanup decisions - Boundary or approval decisions that affected the selected mode - Validation results, remaining blockers, and the completion-report sections -- When present, the completion report should name the used agents, instructions, prompts, skills, and other resources and explain why they were relevant +- When present, the completion report should name the used agents, instructions, skills, and other resources and explain why they were relevant diff --git a/.github/copilot-commit-message-instructions.md b/.github/copilot-commit-message-instructions.md index d762d85..dc25e09 100644 --- a/.github/copilot-commit-message-instructions.md +++ b/.github/copilot-commit-message-instructions.md @@ -20,4 +20,4 @@ ## Examples - `feat(terraform): add policy assignment module` - `fix(workflows): pin checkout action by full SHA` -- `docs(copilot): align prompt and skill references` +- `docs(copilot): align skill and agent references` diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 526879a..0224e25 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -15,11 +15,16 @@ You are an expert software and platform engineer. Protect correctness, security, 2. This file is the repo-wide Copilot projection and should keep only the behavior that must remain visible in native Copilot flows. 3. `.github/copilot-code-review-instructions.md` and `.github/copilot-commit-message-instructions.md` apply when the task is review or commit authoring. 4. Matching `.github/instructions/*.instructions.md` files provide scoped or domain-specific guidance and may override defaults inside their declared scope. -5. Prompts, skills, and agents are on-demand operational assets; use them only when relevant. +5. Skills and agents are on-demand operational assets; use them only when relevant. 6. `.github/INVENTORY.md` is the live catalog of managed assets and is never replaced by `AGENTS.md`. +7. If `.github/local-copilot-overrides.md` exists, read it before relying on synced repo-wide defaults; it is the consumer-local exception layer authorized by `AGENTS.md`. - `internal-sync-*` assets stay sync-specific and must not become second canonical homes for repository-wide policy. - When repository-wide defaults change, update `AGENTS.md` first, then refresh this file, then realign narrower governance assets that reference the change. +- `.github/local-copilot-overrides.md` may override synced defaults from `AGENTS.md` or this file only when the exception makes the conflict, scope, reason, and required disclosure explicit. +- If `.github/local-copilot-overrides.md` exists but declares no active overrides, keep following the synced baseline. +- When following a local override instead of the synced baseline, say that a consumer-local exception is in effect and cite `.github/local-copilot-overrides.md`. +- Do not treat the local override file as inventory or as a replacement for the bridge, projection, and catalog split. ## Language Projection @@ -67,9 +72,22 @@ You are an expert software and platform engineer. Protect correctness, security, - For GitHub Actions pinning, each full SHA must include an adjacent comment with a release or tag reference. - `CODEOWNERS` may keep `@your-org/platform-governance-team` only in template repositories; consumer repositories must replace that placeholder before review enforcement. +## Retained Learning + +- Whenever work reveals a new durable lesson, regardless of whether the task is in planning, review, debugging, or implementation, check whether it was already codified in repository resources when discovered. +- Also treat a repeated or consequential misapplication of an already-codified repository rule as a lesson when the correction is likely to prevent the same mistake in future work. +- Before editing repository-root `LESSONS.md`, read its current on-disk contents and treat them as the source of truth for in-progress local lessons, including uncommitted rows already present on disk. +- When a durable lesson is clear and still uncodified, append one concise, reusable row to the pending table in `LESSONS.md` instead of waiting for task completion; do not regenerate, reorder, or rewrite unrelated rows. +- Treat `LESSONS.md` as a learning ledger, not as canonical policy. Do not dump transient notes, full debugging timelines, sensitive content, or conversational noise into it. +- Preserve unrelated existing lessons in `LESSONS.md`, including local uncommitted ones already on disk. +- If a lesson is later disproven, narrowed, deduplicated, or codified elsewhere in the same task, update or remove only that lesson's row before completion. +- If the same task also codifies the lesson into `AGENTS.md`, this file, a scoped instruction, a skill, or an agent, remove that corresponding row from `LESSONS.md` instead of keeping a codified duplicate there. +- If no durable lesson emerged, do not force a `LESSONS.md` change. + ## Completion Report - End completed operations with `✅ Outcome`. -- When used, also include `🤖 Agents`, `📘 Instructions`, `📝 Prompts`, `🧩 Skills`, and `📦 Other Resources`. +- When used, also include `🤖 Agents`, `📘 Instructions`, `🧩 Skills`, and `📦 Other Resources`. - In each included section, state which resources were used and why they were relevant. +- When `LESSONS.md` was updated, mention it under `📦 Other Resources` with a short reason. - Omit unused categories instead of adding empty or negative sections. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index aff00a6..b1d9381 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,11 +16,3 @@ updates: labels: - "dependencies" - "python" - - package-ecosystem: "terraform" - directory: "/" - schedule: - interval: "weekly" - open-pull-requests-limit: 5 - labels: - - "dependencies" - - "terraform" diff --git a/.github/instructions/internal-github-action-composite.instructions.md b/.github/instructions/internal-github-action-composite.instructions.md index aa3905f..4c9fff5 100644 --- a/.github/instructions/internal-github-action-composite.instructions.md +++ b/.github/instructions/internal-github-action-composite.instructions.md @@ -1,51 +1,17 @@ --- -description: Standards for secure, deterministic GitHub composite actions with explicit input validation. -applyTo: "**/actions/**/action.y*ml,**/workflows/**/action.y*ml" +description: Composite-action-specific standards that extend the GitHub Actions baseline with input validation and safe shell patterns. +applyTo: "**/actions/**/action.y*ml" --- # Composite Action Instructions -## Objective -Define consistent standards for reusable composite actions under `.github/actions/`. +## Scope +- This instruction augments `.github/instructions/internal-github-actions.instructions.md`. +- Keep only composite-specific rules here. -## Mandatory rules -- Keep each composite action focused on one clear responsibility. -- Use explicit `name`, `description`, and typed `inputs`. -- Validate required inputs early and fail fast with clear errors. -- Use English logs and keep output deterministic. -- Avoid embedding secrets in scripts or defaults. -- Prefer shell scripts in `.github/scripts/` for complex logic. - -## Security baseline -- Quote all interpolated shell variables. -- Avoid `eval` and untrusted command execution. -- Minimize permissions in calling workflows. -- Document expected trust model in the action description. -- Pin any `docker://` or container image reference by digest and keep the human-readable tag/version nearby. - -## Shell guidance -- Keep shell snippets inside composite actions aligned with `.github/instructions/internal-bash.instructions.md`. -- When shell logic grows beyond a short validation or orchestration step, move it into a dedicated Bash script under `.github/scripts/`. - -## Minimal example -```yaml -name: "Validate Input" -description: "Validate required inputs before running workflow logic" -inputs: - target: - description: "Target environment" - required: true -runs: - using: "composite" - steps: - - shell: bash - env: - TARGET: ${{ inputs.target }} - run: | - set -euo pipefail - if [[ -z "$TARGET" ]]; then - echo "❌ target is required" >&2 - exit 1 - fi - echo "✅ target input validated" -``` +## Composite-specific rules +- Define explicit `inputs` and validate required values early. +- Pass `${{ inputs.* }}` through `env:` before shell usage. +- Keep `shell: bash` explicit and start shell blocks with `set -euo pipefail`. +- Move longer logic into dedicated scripts instead of large inline `run:` blocks. +- Preserve backward-compatible input and output contracts when modifying an existing composite action. diff --git a/.github/instructions/internal-github-actions.instructions.md b/.github/instructions/internal-github-actions.instructions.md index 201feec..1e63385 100644 --- a/.github/instructions/internal-github-actions.instructions.md +++ b/.github/instructions/internal-github-actions.instructions.md @@ -1,99 +1,30 @@ --- -description: Security and reliability standards for GitHub Actions workflows with SHA pinning and least privilege. -applyTo: "**/workflows/**" +description: Baseline standards for GitHub Actions workflows and composite actions with SHA pinning, least privilege, and deterministic execution. +applyTo: "**/workflows/**,**/actions/**/action.y*ml" --- # GitHub Actions Instructions ## Security baseline - Prefer OIDC over long-lived secrets. -- Pin actions to full-length commit SHAs. -- For each pinned SHA, add an adjacent comment with release/tag and upstream release URL. -- Pin `docker://` references and workflow container images by digest instead of floating tags. -- When an image is pinned by digest, keep the human-readable tag/version in an adjacent comment or nearby reference. +- Pin actions to full-length commit SHAs with adjacent release comments and upstream release URLs. +- Pin `docker://` references and workflow container images by digest. +- When an image is pinned by digest, keep the human-readable tag or version in an adjacent comment or nearby reference. - Keep `permissions` minimal. - Start with `contents: read` and add write scopes only when the job requires them. - Avoid `pull_request_target` for untrusted code. - Pass secrets only through `secrets.*` or protected environments; never hardcode them in `env`. -- Integrate dependency review, SAST, or secret scanning when the workflow is a delivery or release path. -## Workflow baseline -- Start with a descriptive workflow `name` and explicit `on` triggers. -- Set explicit `timeout-minutes`. -- Set `concurrency` when jobs can conflict on shared targets. -- Prefer reusable workflows (`workflow_call`) for repeated pipelines. -- Prefer smaller jobs with explicit `needs` over one monolithic job when phases are logically separate. -- Use `if` conditions deliberately for branch, event, or environment-specific execution. -- Use clear English step names. -- For Terraform jobs: include `fmt -check`, use `-input=false`, and avoid concurrent apply on the same target. -- Keep environment secrets in protected environments when possible. +## Family baseline +- Use clear English step names and deterministic outputs. +- Set explicit `timeout-minutes` for workflows that could otherwise hang. +- Set `concurrency` when jobs can conflict on a shared target. +- Prefer reusable workflows (`workflow_call`) for repeated job orchestration inside one repository. +- Prefer smaller jobs with explicit `needs` over monolithic workflows when phases are logically separate. +- Use `if` conditions deliberately for branch, event, and environment-specific execution. - Keep cache and artifact usage explicit, deterministic, and scoped to real reuse. -- Use matrix strategy only when it improves confidence/cost tradeoff. -- Use `fail-fast: false` only when full matrix visibility matters more than fast failure. +- Use self-hosted runners only for justified hardware, network, or cost reasons, and note the security and maintenance tradeoff. -## Performance and reproducibility -- Use `actions/cache` only for dependencies or outputs with stable keys such as `hashFiles(...)`. -- Prefer `actions/setup-*` built-in caching when it is simpler and equivalent. -- Use `actions/upload-artifact` and `actions/download-artifact` for inter-job handoff instead of rebuilding the same output. -- Default `actions/checkout` to shallow history (`fetch-depth: 1`) unless the job explicitly needs full history. - -## Job and step design -- Keep step boundaries meaningful: setup, build, test, package, deploy. -- Use job `outputs` to pass small structured values and artifacts to pass files. -- Prefer workflow or job-level defaults for shell and working directory when repeated. -- Use self-hosted runners only for justified hardware, network, or cost reasons, and note the security/maintenance tradeoff. - -## Minimal example -```yaml -name: ci - -on: - pull_request: - push: - branches: [main] - -permissions: - contents: read - -timeout-minutes: 20 - -jobs: - build: - runs-on: ubuntu-latest - outputs: - artifact_name: app-build - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 https://github.com/actions/checkout/releases/tag/v6.0.2 - with: - fetch-depth: 1 - - - name: Restore cache - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.2.3 https://github.com/actions/cache/releases/tag/v4.2.3 - with: - path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} - - - name: Build - run: npm ci && npm run build - - - name: Upload artifact - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.6.0 https://github.com/actions/upload-artifact/releases/tag/v4.6.0 - with: - name: app-build - path: dist/ - - deploy: - if: github.ref == 'refs/heads/main' - needs: build - runs-on: ubuntu-latest - environment: production - permissions: - contents: read - id-token: write -steps: - - name: Download artifact - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 https://github.com/actions/download-artifact/releases/tag/v4.1.8 - with: - name: app-build -``` +## Use the skill for deeper guidance +- Load `.github/skills/internal-github-actions/SKILL.md` for workflow-vs-reusable-vs-composite decisions, reusable workflow patterns, and examples. +- Keep this instruction as the auto-loaded baseline; keep authoring depth and examples in the skill. diff --git a/.github/local-copilot-overrides.md b/.github/local-copilot-overrides.md new file mode 100644 index 0000000..82e227b --- /dev/null +++ b/.github/local-copilot-overrides.md @@ -0,0 +1,34 @@ +# Local Copilot Overrides + +This file is the consumer-local exception layer authorized by `AGENTS.md` and referenced by `.github/copilot-instructions.md`. + +It is intentionally local, non-canonical, and outside the mirrored sync baseline. + +## Status + +- No active overrides in this repository. +- When this section stays true, follow the synced baseline from `AGENTS.md` and `.github/copilot-instructions.md`. + +## Activation Contract + +Activate an override only when the repository needs a real local exception that should survive baseline sync updates. + +Each active override must include: + +- `Baseline rule`: the synced rule being overridden. +- `Local scope`: the files, paths, workflows, or situations where the exception applies. +- `Reason`: why the local repository needs the exception. +- `Required disclosure`: the sentence that must be surfaced when the override is followed. +- `Local instruction`: the replacement rule that applies inside the declared scope. + +## Override Template + +Copy this block for each active exception and replace the placeholders. + +### Override: `` + +- `Baseline rule`: `` +- `Local scope`: `` +- `Reason`: `` +- `Required disclosure`: `Consumer-local exception in effect from .github/local-copilot-overrides.md: ` +- `Local instruction`: `` diff --git a/.github/prompts/.gitkeep b/.github/prompts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.github/repo-profiles.yml b/.github/repo-profiles.yml index 9607664..cdde857 100644 --- a/.github/repo-profiles.yml +++ b/.github/repo-profiles.yml @@ -30,10 +30,8 @@ profiles: - instructions/internal-markdown.instructions.md - instructions/internal-yaml.instructions.md - instructions/internal-json.instructions.md - recommended_prompts: - - prompts/internal-github-action.prompt.md recommended_skills: - - skills/internal-cicd-workflow/SKILL.md + - skills/internal-github-actions/SKILL.md backend-java: description: Java service repositories. @@ -41,11 +39,9 @@ profiles: - instructions/internal-java.instructions.md - instructions/internal-github-actions.instructions.md - instructions/internal-markdown.instructions.md - recommended_prompts: - - prompts/internal-add-unit-tests.prompt.md recommended_skills: - skills/internal-project-java/SKILL.md - - skills/internal-cicd-workflow/SKILL.md + - skills/internal-github-actions/SKILL.md backend-nodejs: description: Node.js service repositories. @@ -53,11 +49,9 @@ profiles: - instructions/internal-nodejs.instructions.md - instructions/internal-github-actions.instructions.md - instructions/internal-markdown.instructions.md - recommended_prompts: - - prompts/internal-add-unit-tests.prompt.md recommended_skills: - skills/internal-project-nodejs/SKILL.md - - skills/internal-cicd-workflow/SKILL.md + - skills/internal-github-actions/SKILL.md backend-python: description: Python service repositories. @@ -65,11 +59,9 @@ profiles: - instructions/internal-python.instructions.md - instructions/internal-github-actions.instructions.md - instructions/internal-markdown.instructions.md - recommended_prompts: - - prompts/internal-add-unit-tests.prompt.md recommended_skills: - skills/internal-project-python/SKILL.md - - skills/internal-cicd-workflow/SKILL.md + - skills/internal-github-actions/SKILL.md infrastructure-heavy: description: Infrastructure repositories with Terraform as primary language. @@ -77,8 +69,6 @@ profiles: - instructions/internal-terraform.instructions.md - instructions/internal-github-actions.instructions.md - instructions/internal-yaml.instructions.md - recommended_prompts: - - prompts/internal-terraform-module.prompt.md recommended_skills: - skills/internal-terraform/SKILL.md - skills/internal-cloud-policy/SKILL.md @@ -90,13 +80,8 @@ profiles: - instructions/internal-nodejs.instructions.md - instructions/internal-github-actions.instructions.md - instructions/internal-terraform.instructions.md - recommended_prompts: - - prompts/internal-add-platform.prompt.md - - prompts/internal-add-unit-tests.prompt.md - - prompts/internal-github-action.prompt.md - - prompts/internal-terraform-module.prompt.md recommended_skills: - skills/internal-project-java/SKILL.md - skills/internal-project-nodejs/SKILL.md - - skills/internal-cicd-workflow/SKILL.md + - skills/internal-github-actions/SKILL.md - skills/internal-terraform/SKILL.md diff --git a/.github/scripts/lib/catalog_checks.py b/.github/scripts/lib/catalog_checks.py index df86a2a..8705d54 100644 --- a/.github/scripts/lib/catalog_checks.py +++ b/.github/scripts/lib/catalog_checks.py @@ -191,7 +191,6 @@ def check_duplicate_frontmatter_names(root: Path) -> list[Finding]: groups = { "agent": sorted((root / ".github/agents").glob("*.agent.md")), "skill": sorted((root / ".github/skills").glob("**/SKILL.md")), - "prompt": sorted((root / ".github/prompts").glob("**/*.prompt.md")), } for family, paths in groups.items(): names: dict[str, list[str]] = defaultdict(list) @@ -306,7 +305,6 @@ def collect_catalog_candidate_paths(root: Path) -> list[str]: ( ".github/agents/", ".github/instructions/", - ".github/prompts/", ".github/skills/", ) ) diff --git a/.github/scripts/lib/fingerprinting.py b/.github/scripts/lib/fingerprinting.py index 9b245be..4f7f8e2 100644 --- a/.github/scripts/lib/fingerprinting.py +++ b/.github/scripts/lib/fingerprinting.py @@ -105,8 +105,6 @@ def detect_kind(relative_path: str) -> str: return "agent" if relative_path.startswith(".github/instructions/") and relative_path.endswith(".instructions.md"): return "instruction" - if relative_path.startswith(".github/prompts/"): - return "prompt" return "file" diff --git a/.github/scripts/lib/inventory.py b/.github/scripts/lib/inventory.py index 8283a90..d5e55b4 100644 --- a/.github/scripts/lib/inventory.py +++ b/.github/scripts/lib/inventory.py @@ -5,10 +5,9 @@ from .shared import INVENTORY_PATH, path_list, write_text -SECTION_ORDER = ("Instructions", "Prompts", "Skills", "Agents") +SECTION_ORDER = ("Instructions", "Skills", "Agents") EMPTY_MESSAGES = { "Instructions": "No instruction files currently ship in the live catalog.", - "Prompts": "No prompt files currently ship in the live catalog.", "Skills": "No skill files currently ship in the live catalog.", "Agents": "No agent files currently ship in the live catalog.", } @@ -17,7 +16,6 @@ def collect_inventory_sections(root: Path) -> dict[str, list[str]]: return { "Instructions": path_list(root, ".github/instructions/**/*.instructions.md"), - "Prompts": path_list(root, ".github/prompts/**/*.prompt.md"), "Skills": path_list(root, ".github/skills/**/SKILL.md"), "Agents": path_list(root, ".github/agents/*.agent.md"), } @@ -28,8 +26,6 @@ def sections_from_catalog_paths(paths: list[str]) -> dict[str, list[str]]: for relative_path in sorted(paths): if relative_path.startswith(".github/instructions/") and relative_path.endswith(".instructions.md"): sections["Instructions"].append(relative_path) - elif relative_path.startswith(".github/prompts/") and relative_path.endswith(".prompt.md"): - sections["Prompts"].append(relative_path) elif relative_path.startswith(".github/skills/") and relative_path.endswith("/SKILL.md"): sections["Skills"].append(relative_path) elif relative_path.startswith(".github/agents/") and relative_path.endswith(".agent.md"): diff --git a/.github/scripts/lib/shared.py b/.github/scripts/lib/shared.py index eccbf98..6f37207 100644 --- a/.github/scripts/lib/shared.py +++ b/.github/scripts/lib/shared.py @@ -33,6 +33,7 @@ ".github/DEPRECATION.md", ".github/repo-profiles.yml", ) +LOCAL_COPILOT_OVERRIDES_PATH = ".github/local-copilot-overrides.md" INVENTORY_PATH = ".github/INVENTORY.md" diff --git a/.github/scripts/lib/syncing.py b/.github/scripts/lib/syncing.py index 669474b..6038bc6 100644 --- a/.github/scripts/lib/syncing.py +++ b/.github/scripts/lib/syncing.py @@ -9,6 +9,7 @@ from .fingerprinting import HASH_ALGO, NORMALIZATION_VERSION, build_fingerprint from .shared import ( INVENTORY_PATH, + LOCAL_COPILOT_OVERRIDES_PATH, MANAGED_ROOT_FILES, SyncOperation, SyncPlan, @@ -32,7 +33,7 @@ ".github/internal-sync-copilot-configs.manifest.json", ) TARGET_GITIGNORE_PATH = ".gitignore" -TARGET_SUPERPOWERS_IGNORE_ENTRY = "/docs/superpowers/" +TARGET_SUPERPOWERS_IGNORE_ENTRY = "/tmp/superpowers/" def build_sync_plan(source_root: Path, target_root: Path) -> SyncPlan: @@ -108,6 +109,19 @@ def build_sync_plan(source_root: Path, target_root: Path) -> SyncPlan: ) ) + local_override_path = target_root / LOCAL_COPILOT_OVERRIDES_PATH + if local_override_path.exists(): + local_assets.append(LOCAL_COPILOT_OVERRIDES_PATH) + operations.append( + SyncOperation( + action="preserve", + path=LOCAL_COPILOT_OVERRIDES_PATH, + reason="Preserved consumer-owned local override layer.", + source_hash=None, + target_hash=sha256_file(local_override_path), + ) + ) + for relative_path in LEGACY_SYNC_ARTIFACT_PATHS: legacy_path = target_root / relative_path if not legacy_path.exists(): @@ -125,12 +139,12 @@ def build_sync_plan(source_root: Path, target_root: Path) -> SyncPlan: future_inventory_paths = sorted( catalog_path for catalog_path in source_files - if catalog_path.startswith((".github/agents/", ".github/instructions/", ".github/prompts/", ".github/skills/")) + if catalog_path.startswith((".github/agents/", ".github/instructions/", ".github/skills/")) ) future_inventory_paths.extend( catalog_path for catalog_path in local_assets - if catalog_path.startswith((".github/agents/", ".github/instructions/", ".github/prompts/", ".github/skills/")) + if catalog_path.startswith((".github/agents/", ".github/instructions/", ".github/skills/")) ) generated_inventory = render_inventory_markdown(sections_from_catalog_paths(future_inventory_paths)) @@ -153,9 +167,9 @@ def build_sync_plan(source_root: Path, target_root: Path) -> SyncPlan: generated_gitignore = ensure_superpowers_gitignore_entry(current_gitignore) gitignore_action = "unchanged" if current_gitignore == generated_gitignore else "ensure" gitignore_reason = ( - "Target .gitignore already ignores docs/superpowers." + "Target .gitignore already ignores tmp/superpowers." if gitignore_action == "unchanged" - else "Target .gitignore must ignore docs/superpowers for Superpowers-generated docs artifacts." + else "Target .gitignore must ignore tmp/superpowers for Superpowers-generated working artifacts." ) operations.append( SyncOperation( @@ -185,7 +199,6 @@ def discover_source_sync_files(root: Path) -> set[str]: files = {relative_path for relative_path in MANAGED_ROOT_FILES if (root / relative_path).exists()} files.update(all_files_under(root, ".github/agents")) files.update(all_files_under(root, ".github/instructions")) - files.update(all_files_under(root, ".github/prompts")) files.update(all_files_under(root, MANAGED_SKILL_DIR)) return { relative_path @@ -200,7 +213,6 @@ def discover_target_managed_files(root: Path) -> set[str]: files.add(INVENTORY_PATH) files.update(all_files_under(root, ".github/agents")) files.update(all_files_under(root, ".github/instructions")) - files.update(all_files_under(root, ".github/prompts")) files.update(all_files_under(root, MANAGED_SKILL_DIR)) return { relative_path @@ -213,7 +225,6 @@ def discover_target_excluded_sync_files(root: Path) -> set[str]: files: set[str] = set() files.update(all_files_under(root, ".github/agents")) files.update(all_files_under(root, ".github/instructions")) - files.update(all_files_under(root, ".github/prompts")) files.update(all_files_under(root, MANAGED_SKILL_DIR)) return { relative_path @@ -288,10 +299,10 @@ def ensure_superpowers_gitignore_entry(current_content: str | None) -> str: lines = current_content.splitlines() normalized_entries = {line.strip() for line in lines} accepted_entries = { - "docs/superpowers", - "docs/superpowers/", - "/docs/superpowers", - "/docs/superpowers/", + "tmp/superpowers", + "tmp/superpowers/", + "/tmp/superpowers", + "/tmp/superpowers/", } if normalized_entries & accepted_entries: return current_content if current_content.endswith("\n") else f"{current_content}\n" diff --git a/.github/scripts/lib/token_risks.py b/.github/scripts/lib/token_risks.py index f47928b..c551580 100644 --- a/.github/scripts/lib/token_risks.py +++ b/.github/scripts/lib/token_risks.py @@ -2,10 +2,20 @@ from collections import defaultdict from pathlib import Path - -from .shared import Finding, finding_sort_key, iter_markdown_assets, load_frontmatter, normalize_markdown_text, read_text, significant_text_lines +import re + +from .shared import ( + Finding, + finding_sort_key, + iter_markdown_assets, + load_frontmatter, + normalize_markdown_text, + read_text, + significant_text_lines, +) ROOT_POLICY_MARKERS = ("AGENTS.md", ".github/copilot-instructions.md", ".github/INVENTORY.md") +INVENTORY_LINE_PATTERN = re.compile(r"^- `?\.github/[^`]+`?(?::|\s*$)") def detect_token_risks(root: Path) -> list[Finding]: @@ -37,7 +47,7 @@ def check_bridge_overlap(root: Path) -> list[Finding]: path="AGENTS.md", message=( "AGENTS.md and .github/copilot-instructions.md share too many significant lines, " - f"which increases prompt duplication ({len(shared_lines)} overlapping lines)." + f"which increases duplicated context ({len(shared_lines)} overlapping lines)." ), suggestion="Keep strategic bridge rules in AGENTS.md and move repo-wide Copilot behavior to .github/copilot-instructions.md.", ) @@ -53,7 +63,7 @@ def check_inventory_dumps(root: Path) -> list[Finding]: inventory_lines = [ line for line in read_text(path).splitlines() - if line.strip().startswith("- ") and ".github/" in line + if INVENTORY_LINE_PATTERN.match(line.strip()) ] if len(inventory_lines) < 5: continue @@ -88,7 +98,7 @@ def check_duplicate_markdown_bodies(root: Path) -> list[Finding]: code="duplicate-markdown-body", path=sorted(paths)[0], message=f"Multiple Markdown assets resolve to the same normalized body: {duplicate_paths}.", - suggestion="Remove weaker aliases or move shared logic into one canonical file to reduce duplicated prompt context.", + suggestion="Remove weaker aliases or move shared logic into one canonical file to reduce duplicated context.", ) ) return findings @@ -106,7 +116,7 @@ def check_internal_agent_skill_list_size(root: Path) -> list[Finding]: severity="non-blocking", code="large-skill-list", path=path.relative_to(root).as_posix(), - message=f"The internal agent declares {len(bullets)} optional support skills, which broadens prompt context.", + message=f"The internal agent declares {len(bullets)} optional support skills, which broadens live context.", suggestion="Keep optional skill lists tight and move generic guidance into shared skills when possible.", ) ) diff --git a/.github/security-baseline.md b/.github/security-baseline.md index 38db046..14ee61a 100644 --- a/.github/security-baseline.md +++ b/.github/security-baseline.md @@ -28,11 +28,11 @@ Provide a portable baseline that teams can apply before enabling repository-wide - Protect production environments with required reviewers and deployment rules. - Set explicit `timeout-minutes` and `concurrency` on jobs. -## Prompt and instruction safety +## Instruction and artifact safety - Avoid instructions that request hidden or sensitive data. - Prohibit plaintext tokens, keys, and passwords in examples. - Use explicit guardrails for destructive operations. -- Require deterministic, reviewable output in prompts. +- Require deterministic, reviewable output in generated artifacts. ## Agent safety - Prefer read-only agents for planning/review. @@ -40,8 +40,8 @@ Provide a portable baseline that teams can apply before enabling repository-wide - Require explicit references to policy files for security-sensitive changes. ## Change governance -- Document breaking prompt or instruction changes in `.github/CHANGELOG.md`. -- Use a deprecation window before removing prompts/skills in active use. +- Document breaking instruction, skill, or agent changes in `.github/CHANGELOG.md`. +- Use a deprecation window before removing instructions, skills, or agents in active use. - Keep a rollback path for workflow and policy changes. ## Enforcement status @@ -52,10 +52,10 @@ Provide a portable baseline that teams can apply before enabling repository-wide | Docker image digest pinning | Manual review | `internal-docker.instructions.md` + PR review | | Validate `.github/**` in CI | Not currently automated | n/a | | `shellcheck` on `.github/scripts/` | Automated | pre-commit + CI | -| Secret placeholder avoidance in prompts/examples | Partial | pre-commit hooks + review | +| Secret placeholder avoidance in examples/generated artifacts | Partial | pre-commit hooks + review | | OIDC over long-lived secrets | Manual review | `internal-github-actions.instructions.md` | | IAM least privilege (AWS/Azure/GCP) | Manual review | `internal-code-review` + `internal-terraform` | -| Supply chain hardening | Manual review | `awesome-copilot-github-actions-ci-cd-best-practices.instructions.md` + `internal-code-review` | +| Supply chain hardening | Manual review | `internal-github-actions.instructions.md` + `internal-code-review` | | Branch protection for `.github/**` | Manual review | repository settings | | Read-only reviewer agents | Manual review | agent review | | CHANGELOG-based change governance | Manual review | PR review | diff --git a/.github/skills/internal-agent-development/SKILL.md b/.github/skills/internal-agent-development/SKILL.md index 518140c..218d54e 100644 --- a/.github/skills/internal-agent-development/SKILL.md +++ b/.github/skills/internal-agent-development/SKILL.md @@ -186,7 +186,7 @@ When adapting external agents: 1. Keep the useful mental model or decision sequence. 2. Delete stale runtime-specific frontmatter and copied tool catalog details that do not belong in the internal contract. 3. Rewrite naming into the canonical `internal-*` contract. -4. Replace platform assumptions with repo-local files, prompts, skills, and validations. +4. Replace platform assumptions with repo-local files, skills, and validations. 5. Convert broad expertise claims into concrete routing or output rules. Do not over-compress a well-structured upstream agent. If its strength comes from a clear requirement gate, decision lens, execution order, or response structure, preserve those patterns in repo-local form instead of reducing everything to flat bullets. diff --git a/.github/skills/internal-agent-development/references/conversion-checklist.md b/.github/skills/internal-agent-development/references/conversion-checklist.md index 2dfebf5..2992758 100644 --- a/.github/skills/internal-agent-development/references/conversion-checklist.md +++ b/.github/skills/internal-agent-development/references/conversion-checklist.md @@ -14,7 +14,7 @@ Use this checklist when converting an upstream agent or agent-authoring pattern 1. Rename into the canonical internal contract: `internal-.agent.md`. 2. Rewrite the `description:` so it explains when the internal agent should be selected. 3. Normalize copied tool catalogs to canonical aliases and declare an explicit `tools:` contract for the internal agent. -4. Replace stale runtime-specific tool assumptions with repository-local files, skills, prompts, validators, or current GitHub Copilot frontmatter. +4. Replace stale runtime-specific tool assumptions with repository-local files, skills, validators, or current GitHub Copilot frontmatter. 5. Convert expertise lists into routing rules, role focus, or output expectations. 6. Convert multi-step command flows into `## Execution Workflow` only when recurring orchestration is core to the role. diff --git a/.github/skills/internal-agent-operating-model-engine/references/ownership-maps.md b/.github/skills/internal-agent-operating-model-engine/references/ownership-maps.md index 5f3ef04..c5c5e6f 100644 --- a/.github/skills/internal-agent-operating-model-engine/references/ownership-maps.md +++ b/.github/skills/internal-agent-operating-model-engine/references/ownership-maps.md @@ -13,7 +13,7 @@ Use this reference when the operational model needs a lookup table instead of a | `internal-copilot-audit` | `internal-planning-leader` | Catalog audit, drift analysis, and stale-reference review | | `internal-copilot-docs-research` | `internal-planning-leader` | Contract questions that depend on current GitHub Copilot or MCP behavior | | `internal-change-impact-analysis` | `internal-planning-leader` | Change-impact and architecture-risk analysis | -| `internal-terraform`, `internal-cicd-workflow`, and runtime-specific internal skills | `internal-fast-executor` for local execution, `internal-planning-leader` when design or rollout dominates | Tactical delivery versus strategy split | +| `internal-terraform`, `internal-github-actions`, and runtime-specific internal skills | `internal-fast-executor` for local execution, `internal-planning-leader` when design or rollout dominates | Tactical delivery versus strategy split | | `obra-*` workflows | Cross-agent support | Mandatory when relevant, absent when irrelevant | ## Retired To Canonical Ownership Mapping diff --git a/.github/skills/internal-agent-routing-engine/SKILL.md b/.github/skills/internal-agent-routing-engine/SKILL.md index fe19222..1acd4e2 100644 --- a/.github/skills/internal-agent-routing-engine/SKILL.md +++ b/.github/skills/internal-agent-routing-engine/SKILL.md @@ -44,7 +44,7 @@ Use these heuristics: - Treat explicit review language such as `review`, `audit`, `validate`, `risk`, `merge readiness`, or `regression` as `route-to-review` unless the user clearly asks for implementation. - Treat explicit challenge language such as `challenge this`, `pre-mortem`, `stress-test`, `what am I missing`, `failure modes`, `reframe this`, or `think laterally` as `route-to-challenge`. -- Treat repository-owned authoring of agents, skills, prompts, instructions, routing, or governance as planning unless the change is trivially local and already designed. +- Treat repository-owned authoring of agents, skills, instructions, routing, or governance as planning unless the change is trivially local and already designed. - Treat vague implementation requests as planning when scale, ownership, or rollout is not yet clear. ## Decision Matrix diff --git a/.github/skills/internal-agent-sync-control-center/SKILL.md b/.github/skills/internal-agent-sync-control-center/SKILL.md index 6bc2f14..fb2361c 100644 --- a/.github/skills/internal-agent-sync-control-center/SKILL.md +++ b/.github/skills/internal-agent-sync-control-center/SKILL.md @@ -75,7 +75,7 @@ Load `references/catalog-decision-checklist.md` when you need the detailed keep/ - Compare `description:` lines first. Trigger overlap starts there. - Check whether the repository already has a stronger internal equivalent. - Check whether the asset references files that do not exist. -- Check whether nearby agents, prompts, skills, instructions, `AGENTS.md`, or `.github/copilot-instructions.md` still route to the asset. +- Check whether nearby agents, skills, instructions, `AGENTS.md`, or `.github/copilot-instructions.md` still route to the asset. - Check whether the asset still belongs to the declared managed scope or only survives due to repository drift. ### 2. Pick the Right Outcome diff --git a/.github/skills/internal-agent-sync-control-center/references/fingerprinting-contract.md b/.github/skills/internal-agent-sync-control-center/references/fingerprinting-contract.md index 6438f63..5528e72 100644 --- a/.github/skills/internal-agent-sync-control-center/references/fingerprinting-contract.md +++ b/.github/skills/internal-agent-sync-control-center/references/fingerprinting-contract.md @@ -71,7 +71,6 @@ Infer `kind` from the path when possible: - `.github/skills/*/SKILL.md` -> `skill` - `.github/agents/*.agent.md` -> `agent` - `.github/instructions/*.instructions.md` -> `instruction` -- `.github/prompts/*` -> `prompt` - fallback -> `file` ## Real Change vs Noise diff --git a/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/SKILL.md b/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/SKILL.md index 76b76e2..8cd770d 100644 --- a/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/SKILL.md +++ b/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/SKILL.md @@ -1,6 +1,6 @@ --- name: internal-agent-sync-global-copilot-configs-into-repo -description: Use when aligning a consumer repository to this repository's managed GitHub Copilot baseline, including mirror planning, apply runs, drift checks, and preservation of target `local-*` assets. +description: Use when aligning a consumer repository to this repository's managed GitHub Copilot baseline, including mirror planning, apply runs, drift checks, and preservation of target `local-*` assets plus any `.github/local-copilot-overrides.md` layer. --- # Internal Agent Sync Global Copilot Configs Into Repo @@ -15,6 +15,7 @@ The paired agent should not restate default mode handling, preserved `local-*` b - Align a consumer repository with the managed GitHub Copilot baseline from this repository. - Refresh target `AGENTS.md`, `.github/copilot-instructions.md`, and `.github/INVENTORY.md` to the current bridge model after mirroring. +- Preserve or review a target `.github/local-copilot-overrides.md` file that locally overrides the synced baseline. - Run or interpret `.github/scripts/sync_copilot_catalog.sh` or `.github/scripts/sync_copilot_catalog.py`. - Audit source-target drift before or after a sync. @@ -22,10 +23,11 @@ The paired agent should not restate default mode handling, preserved `local-*` b - Treat this repository as the source of truth. - Keep target assumptions narrow: GitHub Copilot assets live under `.github/` and `AGENTS.md` stays at repository root. -- Preserve target `local-*` assets under mirrored categories and delete target-only non-local assets there during `apply`. +- Preserve target `local-*` assets under mirrored categories, preserve target `.github/local-copilot-overrides.md`, and delete target-only non-local assets there during `apply`. - Exclude source resources named `internal-sync-*` from consumer mirroring and remove any target copies of those resources during `apply`. -- Keep root guidance layered: `AGENTS.md` is the bridge, `.github/copilot-instructions.md` is the repo-wide projection, and `.github/INVENTORY.md` is the live catalog. -- Ensure the target repository `.gitignore` contains an ignore rule for `docs/superpowers/`. +- Do not mirror a source `.github/local-copilot-overrides.md`; it stays consumer-owned even when the source repository has one. +- Keep root guidance layered: `AGENTS.md` is the bridge, `.github/copilot-instructions.md` is the repo-wide projection, `.github/local-copilot-overrides.md` is the consumer-local exception layer, and `.github/INVENTORY.md` is the live catalog. +- Ensure the target repository `.gitignore` contains an ignore rule for `tmp/superpowers/`. - Prefer the bundled sync automation when it matches the requested mode instead of re-deriving the workflow manually. - Keep detailed operating rules in `references/sync-contract.md` instead of re-expanding them in the agent body. @@ -40,7 +42,7 @@ The paired agent should not restate default mode handling, preserved `local-*` b - `plan`: default mode and safest starting point. - `apply`: explicit only, after reviewing a conflict-safe plan and current source findings. -- `audit`: use when source or target drift needs diagnosis before deciding whether to plan or apply. +- `audit`: use when source or target drift needs diagnosis before deciding whether to plan or apply; prefer `.github/scripts/audit_copilot_catalog.sh` plus the sync planner evidence instead of inventing a third sync mode. ## Load On Demand diff --git a/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/references/sync-contract.md b/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/references/sync-contract.md index 8595176..99118d9 100644 --- a/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/references/sync-contract.md +++ b/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/references/sync-contract.md @@ -15,7 +15,6 @@ Mirror these source-managed paths into the consumer repository: - `.github/repo-profiles.yml` - `.github/agents/**` - `.github/instructions/**` -- `.github/prompts/**` - `.github/skills/**`, including bundled `references/`, `assets/`, `scripts/`, `agents/`, and licenses Do not sync `README.md`, changelogs, workflows, templates, or bootstrap helpers unless the user explicitly expands scope. @@ -24,9 +23,11 @@ Do not sync consumer-facing resources whose file or directory name starts with ` ## Target Rules - Preserve target `local-*` assets under mirrored categories and surface them in the plan or final report. +- Preserve target `.github/local-copilot-overrides.md` as a consumer-owned local exception layer and surface it in the plan or final report when present. - Delete target-owned non-`local-*` assets inside mirrored categories during `apply`. +- Do not mirror a source `.github/local-copilot-overrides.md` into consumer repositories. - Keep the target target-agnostic. The default assumptions are only `.github/` and root `AGENTS.md`. -- Ensure the target root `.gitignore` contains an ignore entry for `docs/superpowers/`. +- Ensure the target root `.gitignore` contains an ignore entry for `tmp/superpowers/`. - Treat the `.gitignore` update as target-local hygiene: ensure the required ignore entry exists without mirroring the source repository `.gitignore`. ## Root Guidance Ownership @@ -35,9 +36,10 @@ When root guidance is in scope, keep the target files in these roles: - `AGENTS.md`: strategic bridge, precedence anchor, naming contract, and cross-surface routing guidance - `.github/copilot-instructions.md`: repo-wide GitHub Copilot projection +- `.github/local-copilot-overrides.md`: consumer-local exception layer authorized by `AGENTS.md`; it may override synced defaults only when conflict, scope, reason, and disclosure are explicit - `.github/INVENTORY.md`: exact live catalog generated from target filesystem state -Do not flatten these roles into one file. Do not let target `AGENTS.md` become an inventory dump or a second full copy of `.github/copilot-instructions.md`. +Do not flatten these roles into one file. Do not let target `AGENTS.md` become an inventory dump or a second full copy of `.github/copilot-instructions.md`. Do not let `.github/local-copilot-overrides.md` replace the bridge or catalog roles. ## Tracking Plan Lifecycle @@ -50,7 +52,9 @@ Do not flatten these roles into one file. Do not let target `AGENTS.md` become a ## Automation Entry Points - Preferred wrapper: `.github/scripts/sync_copilot_catalog.sh` +- Audit wrapper: `.github/scripts/audit_copilot_catalog.sh` - Python entry point: `.github/scripts/sync_copilot_catalog.py` +- Audit entry point: `.github/scripts/audit_copilot_catalog.py` - Core implementation: `.github/scripts/lib/syncing.py` - Target manifest: `.github/copilot-sync.manifest.json` @@ -63,7 +67,8 @@ Use the closest existing checks for the touched behavior: 1. `./.github/scripts/check_catalog_consistency.sh --root . --include-token-risks` 2. `./.github/scripts/build_inventory.sh --root .` 3. `./.github/scripts/sync_copilot_catalog.sh plan --target-repo ` -4. `pytest tests/test_sync_and_token_risks.py` when sync automation changes +4. `./.github/scripts/audit_copilot_catalog.sh --root .` when the decision depends on governance drift or local override behavior +5. `pytest tests/test_sync_and_token_risks.py` when sync automation changes If a dedicated contract test is missing, call out the gap explicitly. @@ -73,7 +78,7 @@ Completed runs should make these facts visible: - target analysis and selected mode - root-guidance alignment strategy -- preserved `local-*` assets +- preserved `local-*` assets and `.github/local-copilot-overrides.md` status - target-only cleanup decisions - plan-file status and lifecycle - validation results and remaining blockers diff --git a/.github/skills/internal-cicd-workflow/SKILL.md b/.github/skills/internal-cicd-workflow/SKILL.md deleted file mode 100644 index 6d90d13..0000000 --- a/.github/skills/internal-cicd-workflow/SKILL.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -name: internal-cicd-workflow -description: Use when authoring or revising GitHub Actions workflow files, CI jobs, deployment workflows, or pipeline automation in `.github/workflows/`. ---- - -# CI/CD Workflow Skill - -## When to use -- Create or modify GitHub Actions workflows. -- Add CI/CD jobs (build, test, deploy, lint). -- Add cloud authentication steps for Terraform or deployment. - -Use `internal-devops-core-principles` when the question is delivery strategy, release model, or operating-model health rather than workflow authoring. - -## Mandatory rules -- Prefer OIDC for cloud authentication (no long-lived secrets). -- Pin every action to a full-length SHA. -- Keep `permissions` least-privilege — declare only what the job actually needs. -- Keep step names and operational output in English. -- Follow `.github/instructions/internal-github-actions.instructions.md`. - -## Workflow patterns - -### When to use which - -| Situation | Pattern | -|---|---| -| Simple job sequence (build → test → deploy) | Single workflow with dependent jobs | -| Shared steps across 3+ workflows in the same repo | Reusable workflow (`workflow_call`) | -| Shared steps across multiple repositories | Composite action (see `internal-composite-action`) | -| Conditional deployment per environment | Environment protection rules + manual approval | - -## Auth and workflow examples - -- Load `references/auth-snippets.md` for AWS, Azure, and GCP OIDC snippets. -- Load `references/workflow-example.md` for the minimal workflow skeleton. - -## Common mistakes - -| Mistake | Why it matters | Instead | -|---|---|---| -| Using `permissions: write-all` or omitting permissions entirely | Grants the token maximum access — any compromised step can push code, delete branches, etc. | Declare only the permissions the job needs | -| Pinning actions by tag (`@v4`) instead of SHA | Tags are mutable — a compromised upstream can inject malicious code | Pin to full-length commit SHA | -| Using `secrets.GITHUB_TOKEN` for cross-repo operations | Token is scoped to the current repo only | Use a GitHub App or PAT with minimal scope | -| Long-lived cloud credentials in secrets instead of OIDC | Static credentials can leak and never expire | Configure OIDC federation for AWS/Azure/GCP | -| Missing `environment` protection on production deploys | Anyone who can push to the branch can deploy to prod | Add environment with required reviewers | -| Running `terraform apply` without a plan artifact | Plan drift between PR approval and merge | Save plan in PR job, load in deploy job | -| Duplicating steps across workflows instead of reusable workflow or composite | Maintenance burden grows with every copy | Extract to reusable workflow (same repo) or composite action (cross-repo) | - -## Cross-references -- **internal-composite-action** (`.github/skills/internal-composite-action/SKILL.md`): for reusable composite actions shared across repos. -- **internal-terraform** (`.github/skills/internal-terraform/SKILL.md`): for the Terraform resources deployed by CI/CD. - -## Checklist -- [ ] OIDC configured for cloud auth. -- [ ] All actions pinned by full SHA. -- [ ] `permissions` minimized per job. -- [ ] Environment protection enabled for production. -- [ ] Validation steps included (e.g., `terraform fmt -check`). - -## Validation -- `actionlint` on workflow files (if available). -- Verify no `permissions: write-all` or missing permissions block. -- Verify all `uses:` lines reference full SHA, not tags. diff --git a/.github/skills/internal-cicd-workflow/agents/openai.yaml b/.github/skills/internal-cicd-workflow/agents/openai.yaml deleted file mode 100644 index c100d9b..0000000 --- a/.github/skills/internal-cicd-workflow/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Internal Cicd Workflow" - short_description: "Help with Internal Cicd Workflow tasks" - default_prompt: "Use $internal-cicd-workflow for this task and follow the repository-owned workflow in the skill." diff --git a/.github/skills/internal-cloud-policy/SKILL.md b/.github/skills/internal-cloud-policy/SKILL.md index 2f50ff6..5919240 100644 --- a/.github/skills/internal-cloud-policy/SKILL.md +++ b/.github/skills/internal-cloud-policy/SKILL.md @@ -12,7 +12,7 @@ description: Use when authoring, comparing, or reviewing concrete cloud policy d ## Boundary - Use this skill for concrete policy artifacts or cross-cloud policy comparisons. -- Use `internal-aws-governance`, `internal-azure-governance`, or `internal-gcp-governance` when the main question is IAM, RBAC, operating-model, or guardrail strategy rather than the policy definition itself. +- When the main question is IAM, RBAC, operating-model, or guardrail strategy rather than the policy definition itself, treat it as a governance-design problem instead of a policy-definition task. ## Mandatory rules - Keep scope explicit (organization / folder / subscription / project / management group). @@ -46,10 +46,6 @@ Load `references/policy-templates.md` for AWS SCP, Azure Policy, GCP Org Policy, | No rollback path documented | When policy causes incident, recovery takes hours | Document disable/removal steps before every rollout | | Hardcoded account/subscription/project IDs in policy | Non-portable across environments | Use variables or parameters | -## Cross-references -- **internal-terraform** (`.github/skills/internal-terraform/SKILL.md`): for Terraform resources that deploy policies. -- **internal-cicd-workflow** (`.github/skills/internal-cicd-workflow/SKILL.md`): for CI/CD pipelines that validate and apply policies. - ## Validation - Validate syntax in the target format (JSON / HCL). - Validate policy behavior in non-production scope first. diff --git a/.github/skills/internal-composite-action/SKILL.md b/.github/skills/internal-composite-action/SKILL.md deleted file mode 100644 index 8187c06..0000000 --- a/.github/skills/internal-composite-action/SKILL.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: internal-composite-action -description: Use when creating or modifying a reusable GitHub composite action under `.github/actions/`, especially for shared step logic that should not become a full reusable workflow. ---- - -# Composite Action Skill - -## When to use -- Create a new reusable composite action under `.github/actions/`. -- Modify an existing composite action and preserve compatibility. -- Standardize input validation and shell execution patterns. - -## Composite action vs reusable workflow - -| Factor | Composite action | Reusable workflow | -|---|---|---| -| Granularity | Step-level (runs inside a job) | Job-level (runs as separate job) | -| Secrets access | Inherited from caller job | Must be passed explicitly | -| Outputs | Step outputs only | Workflow outputs | -| Best for | Shared validation, setup, formatting | Full CI/CD pipelines, multi-job orchestration | - -**Rule of thumb**: if the reusable unit is a few steps → composite action. If it is an entire job with its own runner → reusable workflow. - -## Mandatory rules -- Keep the action focused on one responsibility. -- Define explicit `name`, `description`, and typed `inputs`. -- Validate required inputs early and fail fast. -- Use English logs and deterministic output. -- Prefer shell scripts for complex logic instead of large inline blocks. -- Pass expression inputs via `env` — never interpolate `${{ }}` directly in `run:`. -- Quote shell variables. Avoid `eval` and untrusted command execution. -- Keep secrets out of defaults and logs. - -## Minimal template - -Load `references/minimal-template.md` when you need the starter `action.yml` shape. Keep only one focused validation step in the initial template and move longer shell logic into a script early. - -## Common mistakes - -| Mistake | Why it matters | Instead | -|---|---|---| -| Interpolating `${{ inputs.x }}` directly in `run:` | Script injection via crafted input values | Pass through `env:` and use `"$VAR"` in shell | -| Missing `set -euo pipefail` in `run:` blocks | Silent failures, partial execution | Always set strict mode as first line | -| Large inline `run:` blocks (>30 lines) | Hard to read, test, and lint | Extract to a shell script under the action directory | -| No input validation before logic | Cryptic downstream errors | Validate and fail fast at the top of the first step | -| Forgetting `shell: bash` on composite steps | Defaults to `sh` on some runners — different behavior | Always explicit `shell: bash` | -| Breaking existing input contract | Callers silently break without warning | Add new inputs with defaults; deprecate old ones gradually | - -## Cross-references -- **internal-cicd-workflow** (`.github/skills/internal-cicd-workflow/SKILL.md`): for workflows that call composite actions. -- **internal-script-bash** (`.github/skills/internal-script-bash/SKILL.md`): for extracted shell scripts inside the action. - -## Validation -- Inputs documented and validated. -- Shell code is safe (`set -euo pipefail`, quoted vars). -- No secret leakage in logs/defaults. -- Backward compatibility preserved when modifying existing action. diff --git a/.github/skills/internal-composite-action/agents/openai.yaml b/.github/skills/internal-composite-action/agents/openai.yaml deleted file mode 100644 index b168864..0000000 --- a/.github/skills/internal-composite-action/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Internal Composite Action" - short_description: "Help with Internal Composite Action tasks" - default_prompt: "Use $internal-composite-action for this task and follow the repository-owned workflow in the skill." diff --git a/.github/skills/internal-copilot-audit/SKILL.md b/.github/skills/internal-copilot-audit/SKILL.md index 2db1346..9977d92 100644 --- a/.github/skills/internal-copilot-audit/SKILL.md +++ b/.github/skills/internal-copilot-audit/SKILL.md @@ -11,9 +11,9 @@ Treat the declared governance contract in the relevant agent, root `AGENTS.md`, ## Audit Goals -- Detect overlapping skills, prompts, and agents. +- Detect overlapping skills and agents. - Detect hollow assets that point to missing local files or missing companion skills. -- Detect declared skills that have no concrete workflow role in the agent or prompt that declares them. +- Detect declared skills that have no concrete workflow role in the agent or skill surface that declares them. - Detect retired frontmatter and stale runtime-specific wording. - Detect stale or misleading tool contracts in repository-owned internal agents. - Detect weak `AGENTS.md` bridge design. @@ -29,7 +29,7 @@ Treat the declared governance contract in the relevant agent, root `AGENTS.md`, 4. Check declared skill contracts and decorative skill usage. 5. Check trigger overlap. 6. Check bridge coherence between `AGENTS.md` and `.github/copilot-instructions.md`. -7. Check whether prompts, skills, or agents became redundant after internal replacements were added. +7. Check whether skills or agents became redundant after internal replacements were added. 8. Check whether governance files still describe superseded or removed assets. Load `references/audit-checklist.md` when you need the detailed issue taxonomy, flagging criteria, or example findings. diff --git a/.github/skills/internal-copilot-docs-research/SKILL.md b/.github/skills/internal-copilot-docs-research/SKILL.md index 188a593..03d636d 100644 --- a/.github/skills/internal-copilot-docs-research/SKILL.md +++ b/.github/skills/internal-copilot-docs-research/SKILL.md @@ -15,7 +15,6 @@ It is especially useful when the question touches: - repository custom instructions - path-specific instructions -- prompt files - agent skills - custom agents - custom-agent frontmatter fields and environment support @@ -29,7 +28,7 @@ Read the local contract before deciding that the platform should change the repo - `AGENTS.md` - `.github/copilot-instructions.md` -- the relevant local agent, prompt, skill, or instruction file being changed +- the relevant local agent, skill, or instruction file being changed - `references/official-source-map.md` ## Source Priority diff --git a/.github/skills/internal-copilot-docs-research/references/official-source-map.md b/.github/skills/internal-copilot-docs-research/references/official-source-map.md index f05008c..d6e750e 100644 --- a/.github/skills/internal-copilot-docs-research/references/official-source-map.md +++ b/.github/skills/internal-copilot-docs-research/references/official-source-map.md @@ -9,12 +9,12 @@ Use this file as a starting map, not as a substitute for opening the live docs. - `https://docs.github.com/en/copilot/how-tos/configure-custom-instructions` - Use for the high-level entry point to personal, repository, and organization custom instructions. - `https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions?tool=vscode` - - Use for repository custom instructions, prompt files, and environment-specific behavior. + - Use for repository custom instructions and environment-specific behavior. ## Custom agents and skills - `https://docs.github.com/en/copilot/concepts/agents/coding-agent/about-custom-agents` - - Use for what custom agents are, where they are supported, and the high-level model that custom agents can specify prompts, tools, and MCP servers. + - Use for what custom agents are, where they are supported, and the high-level model that custom agents can specify tools and MCP servers. - `https://docs.github.com/en/copilot/reference/custom-agents-configuration` - Use as the primary source for supported frontmatter fields, current tool aliases, MCP tool namespacing, retired `infer`, and environment-specific behavior. - `https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents` @@ -38,7 +38,7 @@ Use this file as a starting map, not as a substitute for opening the live docs. - `https://code.visualstudio.com/docs/copilot/agents/subagents` - Use for subagent invocation, coordinator/worker orchestration patterns, nested subagents, and `agents:` restriction. - `https://code.visualstudio.com/docs/copilot/copilot-customization` - - Use for the VS Code customization overview: instructions, prompt files, agents, and skills. + - Use for the VS Code customization overview: instructions, agents, and skills. - `https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode` - Use for agent mode behavior, tool usage, and session-level agent configuration in VS Code. - `https://code.visualstudio.com/docs/copilot/customization/agent-skills` diff --git a/.github/skills/internal-copilot-instructions-creator/references/review-checklist.md b/.github/skills/internal-copilot-instructions-creator/references/review-checklist.md index 70519f0..5509e43 100644 --- a/.github/skills/internal-copilot-instructions-creator/references/review-checklist.md +++ b/.github/skills/internal-copilot-instructions-creator/references/review-checklist.md @@ -4,7 +4,7 @@ Load this file before finalizing, replacing, or deleting an instruction file. ## Structural Checks -- The file still belongs in `instructions/` rather than `skills/`, `prompts/`, `AGENTS.md`, or `.github/copilot-instructions.md`. +- The file still belongs in `instructions/` rather than `skills/`, `AGENTS.md`, or `.github/copilot-instructions.md`. - The filename uses the repository-owned lowercase hyphenated `.instructions.md` form. - Frontmatter uses only `description` and `applyTo`. - The title and section layout are readable without becoming encyclopedic. diff --git a/.github/skills/internal-docker/SKILL.md b/.github/skills/internal-docker/SKILL.md index 5e430aa..5eb1b27 100644 --- a/.github/skills/internal-docker/SKILL.md +++ b/.github/skills/internal-docker/SKILL.md @@ -33,11 +33,6 @@ Load `references/dockerfile-patterns.md` when you need the canonical multi-stage | One `RUN` per command | Excessive layers, larger image, slower pulls | Combine related commands with `&&` | | Missing `--no-cache-dir` on pip install | Wasted space from pip cache in layer | Always `pip install --no-cache-dir` | -## Cross-references -- **internal-docker.instructions.md** (`.github/instructions/internal-docker.instructions.md`): for repository-level Docker and Compose instruction routing. -- **internal-cicd-workflow** (`.github/skills/internal-cicd-workflow/SKILL.md`): for CI/CD pipelines that build and push images. -- **internal-code-review** (`.github/skills/internal-code-review/SKILL.md`): for reviewing Dockerfile changes. - ## Validation - Verify image references use digests. - Verify non-root user in final stage. diff --git a/.github/skills/internal-github-action-composite/SKILL.md b/.github/skills/internal-github-action-composite/SKILL.md new file mode 100644 index 0000000..91c5fb0 --- /dev/null +++ b/.github/skills/internal-github-action-composite/SKILL.md @@ -0,0 +1,59 @@ +--- +name: internal-github-action-composite +description: Use when creating or modifying a reusable GitHub composite action under `.github/actions/`, especially when input validation, shell safety, or contract compatibility matters. +--- + +# GitHub Composite Action Skill + +## When to use +- Create a new reusable composite action under `.github/actions/`. +- Modify an existing composite action and preserve compatibility. +- Deepen a GitHub Actions task that has already been classified as composite-action authoring. + +## Relationship to the umbrella skill +- `internal-github-actions` is the default entry point for GitHub Actions authoring. +- Load this skill when the work is specifically a composite action or when the umbrella skill decides the reusable unit should move here. + +## Composite action vs reusable workflow + +| Factor | Composite action | Reusable workflow | +|---|---|---| +| Granularity | Step-level reuse inside a job | Job-level orchestration | +| Secrets access | Inherited from the caller job | Passed explicitly to the called workflow | +| Outputs | Step outputs only | Workflow outputs | +| Best for | Shared validation, setup, or step logic | Pipelines with their own jobs, runners, or environments | + +## Mandatory rules +- Follow `.github/instructions/internal-github-action-composite.instructions.md`. +- Pass expression inputs via `env:` instead of interpolating `${{ }}` directly in `run:`. +- Keep `shell: bash` explicit on composite steps. +- Start shell blocks with `set -euo pipefail`. +- Extract long shell logic into a dedicated script early. +- Preserve backward compatibility when modifying existing inputs or outputs. + +## Minimal template + +Load `references/minimal-template.md` when you need the starter `action.yml` shape. Keep the initial template small, validate required inputs early, and move longer logic into a script instead of growing a large inline `run:` block. + +## Common mistakes + +| Mistake | Why it matters | Instead | +|---|---|---| +| Interpolating `${{ inputs.x }}` directly in `run:` | Crafted input values can turn into shell injection | Pass the value through `env:` and use quoted shell variables | +| Missing `set -euo pipefail` in `run:` blocks | Silent failures and partial execution become hard to spot | Make strict mode the first line of every shell block | +| Large inline `run:` blocks | They are hard to read, lint, and review | Extract the logic into a dedicated script early | +| No input validation before the main logic | Failures surface later with weaker error messages | Validate required inputs in the first step and fail fast | +| Forgetting `shell: bash` on composite steps | Runner defaults can differ and change behavior | Keep `shell: bash` explicit | +| Breaking an existing input or output contract | Callers can fail without a clear migration path | Add new fields compatibly and preserve the old contract where possible | + +## Cross-references + +- **internal-github-actions** (`.github/skills/internal-github-actions/SKILL.md`): for the umbrella GitHub Actions lane and reuse-pattern selection. +- **internal-script-bash** (`.github/skills/internal-script-bash/SKILL.md`): for extracted shell scripts inside the action. + +## Validation + +- Inputs are explicit and validated early. +- Shell code uses `set -euo pipefail`, quoted variables, and explicit `shell: bash`. +- Longer logic moves into a dedicated script instead of staying inline. +- Existing input and output contracts remain backward compatible. diff --git a/.github/skills/internal-github-action-composite/agents/openai.yaml b/.github/skills/internal-github-action-composite/agents/openai.yaml new file mode 100644 index 0000000..693ebed --- /dev/null +++ b/.github/skills/internal-github-action-composite/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Internal GitHub Action Composite" + short_description: "Help with Internal GitHub composite action tasks" + default_prompt: "Use $internal-github-action-composite for this task and follow the repository-owned workflow in the skill." diff --git a/.github/skills/internal-composite-action/references/minimal-template.md b/.github/skills/internal-github-action-composite/references/minimal-template.md similarity index 100% rename from .github/skills/internal-composite-action/references/minimal-template.md rename to .github/skills/internal-github-action-composite/references/minimal-template.md diff --git a/.github/skills/internal-github-actions/SKILL.md b/.github/skills/internal-github-actions/SKILL.md new file mode 100644 index 0000000..11283a9 --- /dev/null +++ b/.github/skills/internal-github-actions/SKILL.md @@ -0,0 +1,66 @@ +--- +name: internal-github-actions +description: Use when authoring or revising GitHub Actions workflows, reusable workflows, or deciding when shared step logic should move into a composite action. +--- + +# GitHub Actions Skill + +## When to use +- Create or modify GitHub Actions workflows under `.github/workflows/`. +- Create or modify reusable workflows exposed through `workflow_call`. +- Decide whether repeated step logic should stay inline, move to a reusable workflow, or move to a composite action. +- Add CI/CD jobs such as build, test, lint, release, or deployment. + +Use `internal-devops-core-principles` when the question is delivery strategy, release model, or operating-model health rather than workflow authoring. + +## Mandatory rules +- Follow `.github/instructions/internal-github-actions.instructions.md`. +- Prefer OIDC for cloud authentication. +- Pin every third-party action to a full-length SHA with adjacent release comment. +- Keep `permissions` least-privilege. +- Keep step names and logs in English. + +## Choose the right reuse pattern + +| Situation | Pattern | +|---|---| +| Simple pipeline in one repository | Standard workflow | +| Repeated job orchestration inside one repository | Reusable workflow (`workflow_call`) | +| Shared step logic across repositories or many workflows | Composite action | +| Composite action authoring or contract changes | Load `internal-github-action-composite` | + +## Auth and workflow examples + +- Load `references/auth-snippets.md` for AWS, Azure, and GCP OIDC snippets. +- Load `references/workflow-example.md` for the minimal workflow skeleton. + +## Common mistakes + +| Mistake | Why it matters | Instead | +|---|---|---| +| Using `permissions: write-all` or omitting permissions entirely | Grants the token maximum access and widens the blast radius of a compromised step | Declare only the permissions the job needs | +| Pinning actions by tag (`@v4`) instead of SHA | Tags are mutable and can be retargeted upstream | Pin to a full-length commit SHA with a release comment | +| Using `secrets.GITHUB_TOKEN` for cross-repo operations | The token is scoped to the current repository only | Use a GitHub App or PAT with minimal scope | +| Long-lived cloud credentials in secrets instead of OIDC | Static credentials can leak and do not expire automatically | Configure OIDC federation for AWS, Azure, or GCP | +| Missing `environment` protection on production deploys | Anyone who can push to the branch can deploy to production | Add an environment with required reviewers | +| Running `terraform apply` without a plan artifact | Plan drift can occur between review and deployment | Save the plan in the PR job and load it in the deploy job | +| Duplicating steps across workflows instead of reusable workflow or composite action | Maintenance burden grows with every copy | Extract to a reusable workflow in one repo or a composite action across repos | + +## Cross-references + +- **internal-github-action-composite** (`.github/skills/internal-github-action-composite/SKILL.md`): for composite-action authoring and compatibility-sensitive contract changes. +- **internal-terraform** (`.github/skills/internal-terraform/SKILL.md`): for the Terraform resources deployed by CI/CD. + +## Checklist + +- [ ] OIDC configured for cloud auth. +- [ ] All third-party actions pinned by full SHA with release comments. +- [ ] `permissions` minimized per job. +- [ ] Environment protection enabled for production. +- [ ] Validation steps included where the workflow changes infrastructure or releases. + +## Validation + +- `actionlint` on workflow files, if available. +- Verify there is no `permissions: write-all` and no missing permissions block where least privilege matters. +- Verify all `uses:` lines reference full SHAs instead of tags. diff --git a/.github/skills/internal-github-actions/agents/openai.yaml b/.github/skills/internal-github-actions/agents/openai.yaml new file mode 100644 index 0000000..eb79e23 --- /dev/null +++ b/.github/skills/internal-github-actions/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Internal GitHub Actions" + short_description: "Help with Internal GitHub Actions tasks" + default_prompt: "Use $internal-github-actions for this task and follow the repository-owned workflow in the skill." diff --git a/.github/skills/internal-cicd-workflow/references/auth-snippets.md b/.github/skills/internal-github-actions/references/auth-snippets.md similarity index 100% rename from .github/skills/internal-cicd-workflow/references/auth-snippets.md rename to .github/skills/internal-github-actions/references/auth-snippets.md diff --git a/.github/skills/internal-cicd-workflow/references/workflow-example.md b/.github/skills/internal-github-actions/references/workflow-example.md similarity index 100% rename from .github/skills/internal-cicd-workflow/references/workflow-example.md rename to .github/skills/internal-github-actions/references/workflow-example.md diff --git a/.github/skills/internal-github-strategic/SKILL.md b/.github/skills/internal-github-strategic/SKILL.md index 91d2255..babda0c 100644 --- a/.github/skills/internal-github-strategic/SKILL.md +++ b/.github/skills/internal-github-strategic/SKILL.md @@ -138,7 +138,7 @@ Include: Use when the next need is rulesets, permissions, OIDC, secret posture, environments, or Copilot guardrail definition. - `internal-github-operations` Use when the next need is Actions health, runner validation, audit evidence, reporting, drift checks, or post-rollout checks. -- `internal-cicd-workflow`, `internal-script-python`, `internal-script-bash` +- `internal-github-actions`, `internal-script-python`, `internal-script-bash` Use when the decision is settled and implementation begins. ## Anti-patterns diff --git a/.github/skills/internal-kubernetes-deployment/SKILL.md b/.github/skills/internal-kubernetes-deployment/SKILL.md index 3eaf845..a8a5bf8 100644 --- a/.github/skills/internal-kubernetes-deployment/SKILL.md +++ b/.github/skills/internal-kubernetes-deployment/SKILL.md @@ -9,8 +9,8 @@ Use this skill for operational Kubernetes delivery work after the platform direc ## Boundary -- Use `internal-kubernetes` when the right Kubernetes lane is still unclear or the request mixes platform architecture with delivery work. -- Use `antigravity-kubernetes-architect` for cluster architecture, GitOps operating model, service mesh, or multi-cluster strategy. +- Use this skill only after the platform or cluster direction is already chosen. +- If the real question is cluster architecture, GitOps operating model, service mesh, or multi-cluster strategy, treat it as a platform-design problem rather than a manifest-delivery task. - Keep this skill focused on workload manifests, rollout safety, and production hardening. ## Operational Workflow diff --git a/.github/skills/internal-kubernetes/references/routing-matrix.md b/.github/skills/internal-kubernetes/references/routing-matrix.md index e7216bb..a0b139d 100644 --- a/.github/skills/internal-kubernetes/references/routing-matrix.md +++ b/.github/skills/internal-kubernetes/references/routing-matrix.md @@ -8,7 +8,7 @@ Use this reference when a request touches more than one Kubernetes concern and t | Workload manifests under `k8s/`, `manifests/`, `deploy/`, or Helm templates | `internal-kubernetes-deployment` | The work is about controller choice, rollout behavior, probes, exposure, config, or hardening | Let `awesome-copilot-kubernetes-manifests.instructions.md` auto-apply for YAML hygiene | | Production rollout safety, readiness, rollback, or observability checks for an existing workload | `internal-kubernetes-deployment` | The platform direction is already chosen and the remaining risk is operational delivery | Pair with repository validation or deployment checks that already exist in the target repo | | Mixed request that starts broad and then narrows into manifests or rollout settings | `internal-kubernetes` first, then the winning downstream skill | The main value is choosing the lane before doing detailed work | State the split explicitly so only one downstream skill becomes the detailed owner | -| Kubernetes delivery that also changes GitHub Actions workflows | `internal-kubernetes-deployment` plus `internal-cicd-workflow` | One skill owns the workload delivery shape and the other owns CI/CD workflow changes | Keep workflow authoring out of the Kubernetes skill unless the YAML pipeline is the actual target | +| Kubernetes delivery that also changes GitHub Actions workflows | `internal-kubernetes-deployment` plus `internal-github-actions` | One skill owns the workload delivery shape and the other owns CI/CD workflow changes | Keep workflow authoring out of the Kubernetes skill unless the YAML pipeline is the actual target | ## Anti-confusion notes diff --git a/.github/skills/internal-pr-editor/SKILL.md b/.github/skills/internal-pr-editor/SKILL.md index 79f8a0f..ed88ca6 100644 --- a/.github/skills/internal-pr-editor/SKILL.md +++ b/.github/skills/internal-pr-editor/SKILL.md @@ -3,7 +3,7 @@ name: internal-pr-editor description: Use when writing or updating a pull request title or body from a real diff, specification, or repository template, and the output must stay aligned with the actual change. --- -# TechAI PR Editor — Skill +# Internal PR Editor ## When to use - Create a new pull request description. diff --git a/.github/skills/internal-project-java/SKILL.md b/.github/skills/internal-project-java/SKILL.md index a36ecde..50283a1 100644 --- a/.github/skills/internal-project-java/SKILL.md +++ b/.github/skills/internal-project-java/SKILL.md @@ -26,7 +26,7 @@ Load `references/examples.md` when you need a minimal class or test example. - For modify tasks: edit implementation first, run existing tests, then update tests only for intentional behavior changes. ## Spring coordination -- Keep Spring-specific design decisions lightweight here and use `internal-spring-boot-development` when controller, configuration, repository, or test-slice choices dominate the task. +- Keep Spring-specific design decisions lightweight here and treat controller, configuration, repository, or test-slice-heavy work as a separate framework-focused lane. - Prefer constructor injection with `private final` dependencies and keep transaction boundaries narrow. ## Modern Java guidance @@ -49,12 +49,6 @@ Load `references/examples.md` when you need a minimal class or test example. | Adding virtual threads without checking execution model | Can mask blocking or context propagation issues | Adopt them only when runtime support and workload fit are clear | | Over-using inheritance for code reuse | Rigid hierarchies, fragile base class problem | Prefer composition and delegation | -## Cross-references -- **internal-code-review** (`.github/skills/internal-code-review/SKILL.md`): for reviewing Java code (see `.github/skills/internal-code-review/references/anti-patterns-java.md`). -- **internal-docker** (`.github/skills/internal-docker/SKILL.md`): for containerizing Java apps. -- **internal-oop-design-patterns** (`.github/skills/internal-oop-design-patterns/SKILL.md`): for object collaboration refactors and pattern selection that go beyond baseline Java guidance. -- **internal-spring-boot-development** (`.github/skills/internal-spring-boot-development/SKILL.md`): for Spring Boot-specific application, configuration, persistence, and test decisions. - ## Validation - Compile with `mvn compile` or `gradle build`. - Run tests with `mvn test` or `gradle test`. diff --git a/.github/skills/internal-project-nodejs/SKILL.md b/.github/skills/internal-project-nodejs/SKILL.md index a9fe1a0..13aba28 100644 --- a/.github/skills/internal-project-nodejs/SKILL.md +++ b/.github/skills/internal-project-nodejs/SKILL.md @@ -49,10 +49,6 @@ Load `references/examples.md` when you need a minimal module or test example. | Changing module system casually | Breaks tooling, imports, and runtime behavior | Stay with the existing ESM/CJS choice unless the migration is explicit | | Using `Promise.all` on dependent work | Masks ordering assumptions and makes failures harder to interpret | Keep dependent async steps sequential | -## Cross-references -- **internal-code-review** (`.github/skills/internal-code-review/SKILL.md`): for reviewing Node.js code (see `.github/skills/internal-code-review/references/anti-patterns-nodejs.md`). -- **internal-docker** (`.github/skills/internal-docker/SKILL.md`): for containerizing Node.js apps. - ## Validation - Run tests: `node --test` or `npm test`. - Lint: `npx eslint .` when configured. diff --git a/.github/skills/internal-project-python/SKILL.md b/.github/skills/internal-project-python/SKILL.md index 453e25d..9a26410 100644 --- a/.github/skills/internal-project-python/SKILL.md +++ b/.github/skills/internal-project-python/SKILL.md @@ -12,10 +12,10 @@ Follow `.github/instructions/internal-python.instructions.md` for the baseline P - Refactoring or extending existing Python application components. - Reusable Python code whose primary contract is imported behavior rather than operator-facing execution. -## Boundary with internal-script-python -- **This skill**: structured package, library, or application components whose primary contract is reusable domain, service, or framework behavior. -- **internal-script-python**: standalone operational tools, CLI entrypoints, and small script toolkits whose primary contract is direct execution. -- A `lib/` folder, root-level tests, or multiple entrypoints alone do not make a tool `internal-project-python`. +## Boundary +- This skill covers structured package, library, or application components whose primary contract is reusable domain, service, or framework behavior. +- Small operator-facing tools remain out of scope even when they have multiple files or tests. +- A `lib/` folder, root-level tests, or multiple entrypoints alone do not make a tool application code. ## Application-specific guidance - Use type hints on public APIs and keep data contracts explicit. @@ -56,11 +56,6 @@ Load `references/examples.md` when you need a minimal module or test example. | Treating line coverage as the goal | Inflates test volume without improving defect detection | Target coverage around changed behavior and risky paths | | God classes with 10+ methods | Hard to test, hard to reason about | Split by responsibility into focused classes | -## Cross-references -- **internal-script-python** (`.github/skills/internal-script-python/SKILL.md`): for standalone scripts. -- **internal-code-review** (`.github/skills/internal-code-review/SKILL.md`): for reviewing Python code (see `.github/skills/internal-code-review/references/anti-patterns-python.md`). -- **internal-docker** (`.github/skills/internal-docker/SKILL.md`): for containerizing Python apps. - ## Validation - `python -m compileall ` (syntax check) - `pytest tests/` (run tests) diff --git a/.github/skills/internal-script-bash/SKILL.md b/.github/skills/internal-script-bash/SKILL.md index 369b439..cfa6126 100644 --- a/.github/skills/internal-script-bash/SKILL.md +++ b/.github/skills/internal-script-bash/SKILL.md @@ -33,10 +33,6 @@ Load `references/templates.md` when you need the starter script, the standard ar | Destructive commands without rerun safety | Repeated execution can corrupt state or surprise operators | Add `--dry-run` and make the mutation idempotent | | Rewriting parser or cleanup scaffolding from scratch | Operator UX and failure handling drift between scripts | Reuse the starter and helper patterns from `references/templates.md` | -## Cross-references -- **internal-composite-action** (`.github/skills/internal-composite-action/SKILL.md`): for Bash inside composite actions. -- **internal-code-review** (`.github/skills/internal-code-review/SKILL.md`): for reviewing Bash code (see `.github/skills/internal-code-review/references/anti-patterns-bash.md`). - ## Validation - `bash -n script.sh` (syntax check) - `shellcheck -s bash script.sh` (lint) diff --git a/.github/skills/internal-script-python/SKILL.md b/.github/skills/internal-script-python/SKILL.md index 28e151b..52db518 100644 --- a/.github/skills/internal-script-python/SKILL.md +++ b/.github/skills/internal-script-python/SKILL.md @@ -13,10 +13,10 @@ Follow `.github/instructions/internal-python.instructions.md` for the baseline P - CLI tools, one-off automation, data processing. - Small multi-entrypoint toolkits whose primary contract is operator-facing execution rather than reusable package APIs. -## Boundary with internal-project-python -- **This skill**: standalone operational tools, CLI entrypoints, and small script toolkits whose primary contract is direct execution. -- **internal-project-python**: structured package, library, and application components whose primary contract is imported behavior, service boundaries, or framework-owned flows. -- A tool does not become `internal-project-python` just because it has multiple files, a `lib/` folder, or root-level tests. +## Boundary +- This skill covers standalone operational tools, CLI entrypoints, and small script toolkits whose primary contract is direct execution. +- A tool does not become application code just because it has multiple files, a `lib/` folder, or root-level tests. +- Move out of this lane only when the primary contract becomes imported behavior, service boundaries, or framework-owned flows. ## Script-specific guidance - Standalone tools should default to a dedicated folder or toolkit root, not a loose top-level `.py` file. @@ -87,10 +87,6 @@ Keep these rules visible while drafting: | Rejecting a useful dependency just to keep dependency count low | Optimizes the wrong thing and increases custom code | Optimize for simpler final code and justified value, not dependency minimization | | Forcing async or framework abstractions into a simple tool | Raises complexity without improving the script | Keep the script synchronous and direct unless concurrency is essential | -## Cross-references -- **internal-project-python** (`.github/skills/internal-project-python/SKILL.md`): for structured application code. -- **internal-code-review** (`.github/skills/internal-code-review/SKILL.md`): for reviewing Python code (see `.github/skills/internal-code-review/references/anti-patterns-python.md`). - ## Validation - `python -m py_compile .py` (syntax check) - `bash -n run.sh` (launcher syntax check, only when `run.sh` exists) diff --git a/.github/skills/internal-spring-boot-development/SKILL.md b/.github/skills/internal-spring-boot-development/SKILL.md index 2fc4a50..f99b1b0 100644 --- a/.github/skills/internal-spring-boot-development/SKILL.md +++ b/.github/skills/internal-spring-boot-development/SKILL.md @@ -5,7 +5,7 @@ description: Use when Spring Boot framework choices drive the work, such as cont # Internal Spring Boot Development -Follow `.github/instructions/internal-java.instructions.md` and `.github/skills/internal-project-java/SKILL.md` for the baseline Java rules. Use this skill only when the Spring Boot framework choices materially affect the design, wiring, testing, or configuration. +Follow `.github/instructions/internal-java.instructions.md` for the baseline Java rules. Use this skill only when the Spring Boot framework choices materially affect the design, wiring, testing, or configuration. ## Workflow diff --git a/.github/skills/internal-terraform/SKILL.md b/.github/skills/internal-terraform/SKILL.md index 7b70df2..1d294e5 100644 --- a/.github/skills/internal-terraform/SKILL.md +++ b/.github/skills/internal-terraform/SKILL.md @@ -78,11 +78,6 @@ Load `references/template-examples.md` when you need a minimal inline feature ex | Missing `prevent_destroy` on critical production resources | Accidental deletion during `terraform apply` | Add lifecycle for databases, DNS zones, encryption keys | | `default = ""` instead of `default = null` for optional strings | Empty string passes validation but means "no value" ambiguously | Use `null` for truly optional inputs | -## Cross-references -- **internal-cloud-policy** (`.github/skills/internal-cloud-policy/SKILL.md`): for governance policies (SCP, Azure Policy, GCP Org Policy) applied alongside Terraform infra. -- **internal-cicd-workflow** (`.github/skills/internal-cicd-workflow/SKILL.md`): for CI/CD pipelines that run `terraform plan/apply`. -- **terraform-terraform-test** (`.github/skills/terraform-terraform-test/SKILL.md`): for `.tftest.hcl` authoring and Terraform native test workflows. - ## Validation - `terraform fmt -check -recursive` - `terraform validate` diff --git a/.github/skills/obra-dispatching-parallel-agents/SKILL.md b/.github/skills/obra-dispatching-parallel-agents/SKILL.md index 0065cc0..e10d9c1 100644 --- a/.github/skills/obra-dispatching-parallel-agents/SKILL.md +++ b/.github/skills/obra-dispatching-parallel-agents/SKILL.md @@ -83,7 +83,7 @@ When agents return: ## Agent Prompt Structure -Good agent prompts are: +Good agent requests are: 1. **Focused** - One clear problem domain 2. **Self-contained** - All context needed to understand the problem 3. **Specific about output** - What should the agent return? diff --git a/.github/skills/obra-using-superpowers/references/codex-tools.md b/.github/skills/obra-using-superpowers/references/codex-tools.md index 73212df..cc9634d 100644 --- a/.github/skills/obra-using-superpowers/references/codex-tools.md +++ b/.github/skills/obra-using-superpowers/references/codex-tools.md @@ -32,16 +32,16 @@ from built-in roles (`default`, `explorer`, `worker`). When a skill says to dispatch a named agent type: -1. Find the agent's prompt file (e.g., `agents/code-reviewer.md` or the skill's - local prompt template like `code-quality-reviewer-prompt.md`) -2. Read the prompt content +1. Find the agent's task file (e.g., `agents/code-reviewer.md` or the skill's + local task template like `code-quality-reviewer-task.md`) +2. Read the task content 3. Fill any template placeholders (`{BASE_SHA}`, `{WHAT_WAS_IMPLEMENTED}`, etc.) 4. Spawn a `worker` agent with the filled content as the `message` | Skill instruction | Codex equivalent | |-------------------|------------------| | `Task tool (internal-review-guard)` | `spawn_agent(agent_type="worker", message=...)` with `code-reviewer.md` content | -| `Task tool (general-purpose)` with inline prompt | `spawn_agent(message=...)` with the same prompt | +| `Task tool (general-purpose)` with inline task text | `spawn_agent(message=...)` with the same task text | ### Message framing diff --git a/AGENTS.md b/AGENTS.md index 973d0aa..e751c95 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,9 +11,9 @@ This file is the stable entrypoint for the repository instruction architecture. ## Cross-Surface Contract 1. Use `.github/copilot-instructions.md` as the repo-wide Copilot projection. -2. Use `.github/INVENTORY.md` for the exact live catalog of instructions, prompts, skills, and agents. +2. Use `.github/INVENTORY.md` for the exact live catalog of instructions, skills, and agents. 3. Use `.github/instructions/` for path-specific or domain-specific projections. -4. Use `.github/prompts/`, `.github/skills/`, and `.github/agents/` only when they are relevant to the current task. +4. Use `.github/skills/` and `.github/agents/` only when they are relevant to the current task. 5. Keep policy, projections, and inventory separate instead of mixing them into one file. ## Precedence Model @@ -59,6 +59,24 @@ This file is the stable entrypoint for the repository instruction architecture. - When a sync or catalog workflow changes a repository-wide default, update the canonical owner first and then realign downstream projections or sync surfaces in the same pass. - Do not treat removed validators, sync scripts, contract tests, or historical aliases as active policy unless they exist on disk and are reintroduced deliberately. +## Consumer Override Layer + +- Consumer repositories may keep a non-mirrored `.github/local-copilot-overrides.md` file as a consumer-owned local exception layer. +- That file may override synced defaults from `AGENTS.md` or `.github/copilot-instructions.md` only inside the consumer repository and only when each exception states the overridden baseline rule, local scope, reason, and required disclosure. +- If the file exists but declares no active overrides, keep the synced baseline authoritative. +- When a response follows a local override, it must say that a consumer-local exception is in effect and cite `.github/local-copilot-overrides.md`. +- Keep the local override file local. Do not mirror it from this standards repository, do not treat it as inventory, and do not use it to collapse the separate roles of `AGENTS.md`, `.github/copilot-instructions.md`, and `.github/INVENTORY.md`. +- The local override layer must not redefine the ownership meaning of `internal-*`, `local-*`, or `internal-sync-*`; use it for repo-local exceptions, not for replacing the bridge model. + +## Retained Learning + +- Root `LESSONS.md` is the repository learning ledger for durable lessons discovered during repository work, regardless of phase. +- Record or codify a durable lesson as soon as it becomes clear enough to be reusable; do not wait for task completion only because the work is still in planning, review, debugging, or implementation. +- Keep `LESSONS.md` non-canonical. It must not replace `AGENTS.md`, `.github/copilot-instructions.md`, scoped instructions, skills, or agents. +- Keep `LESSONS.md` append-preserving by default: preserve unrelated rows already on disk, including local uncommitted lessons, and change a specific row only when that same lesson is being codified, disproven, narrowed, or deduplicated. +- Durable corrections to repeated or consequential misapplication of existing repository rules may also be retained as lessons. +- Keep detailed retained-learning behavior in `.github/copilot-instructions.md`; keep only the strategic boundary here. + ## Volatile Artifacts - Transient planning, brainstorming, and other Superpowers-generated working files must not be written under `docs/`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9921d7..dbd219a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,9 +22,8 @@ This repository is the source baseline for reusable GitHub Copilot customization ## Adding or updating assets - Instructions: keep frontmatter `description` and `applyTo`, use repository-agnostic wording, and avoid stack duplication already covered by a skill. -- Prompts: require `name`, `description`, `agent`, and `argument-hint`, plus `## Instructions`, `## Validation`, and `## Minimal example`. - Skills: keep `name`, `description`, `## When to use`, and one validation/testing section. -- Agents: keep `name`, `description`, `tools`, `## Objective`, and `## Restrictions`. +- Agents: keep `name`, `description`, `tools`, and the current section structure used in this repository: `## Role`, `## Mandatory Engine Skills`, `## Optional Support Skills`, `## Core Rules`, `## Routing Rules`, `## Boundary Definition`, and `## Output Expectations`. ## Validation before PR diff --git a/COPILOT_REVIEW.md b/COPILOT_REVIEW.md deleted file mode 100644 index 1339754..0000000 --- a/COPILOT_REVIEW.md +++ /dev/null @@ -1,617 +0,0 @@ -# Copilot Configuration Review — cloud-strategy.github - -> **Status**: Historical audit record. Some findings below refer to removed validators, removed sync scripts, removed tests, or earlier bridge architecture states. Use `AGENTS.md`, `.github/copilot-instructions.md`, and `INTERNAL_CONTRACT.md` as the current contract. -> **Generated**: 2026-03-09 -> **Scope**: Full audit of GitHub Copilot customization assets in `cloud-strategy.github` (global standards repository) -> **Purpose**: Actionable findings for Codex to fix. Each item includes the exact file, the problem, and the concrete fix required. -> **Note**: This review supersedes findings in `ANALYSIS_REPORT.md` (dated 2025-07-17). Items already resolved since that report are not repeated here. - ---- - -## Table of Contents - -- [Executive Summary](#executive-summary) -- [Critical Findings](#critical-findings) -- [Major Findings](#major-findings) -- [Minor Findings](#minor-findings) -- [Nit Findings](#nit-findings) -- [Architecture & Token Optimization](#architecture--token-optimization) -- [Missing Assets & Gaps](#missing-assets--gaps) -- [Action Checklist](#action-checklist) - ---- - -## Executive Summary - -The `cloud-strategy.github` repository is an impressive and well-thought-out framework for managing GitHub Copilot customization at scale. Since the original ANALYSIS_REPORT (July 2025), significant improvements have been made: prompt duplication has been consolidated to canonical origin-prefixed names, the sync script has grown to 2300+ lines with 20 tests, repo-only agents have been properly isolated, and the validator is robust at ~1200 lines. The framework is clearly production-grade. - -However, this review identifies areas where Codex effectiveness can be further improved: **token budget waste from redundant content**, **missing infrastructure for key consumer stacks**, **test coverage gaps for the validator bash script**, and **governance enforcement blind spots** that reduce the framework's reliability at scale. - -| Severity | Count | -|----------|-------| -| Critical | 1 | -| Major | 9 | -| Minor | 10 | -| Nit | 7 | - ---- - -## Critical Findings - -### C-01: `bootstrap-copilot-config.sh` is still active without deprecation — overlaps with sync script - -**File**: `.github/scripts/bootstrap-copilot-config.sh` - -The rsync-based bootstrap script and the manifest-based sync script (`internal-sync-copilot-configs.py`) serve overlapping purposes. The sync script is far superior (SHA tracking, conflict detection, profile-aware selection, JSON reports, conservative merge). The bootstrap script does destructive `--clean` syncs with no manifest tracking, no conflict detection, and no reporting. This creates confusion for Codex about which tool to use and risks destructive operations on consumer repos. - -The ANALYSIS_REPORT (item 2.4) flagged this in July 2025 but it remains unresolved. - -**Fix**: -1. Add a deprecation notice to the header of `bootstrap-copilot-config.sh`: -```bash -# ⚠️ DEPRECATED: Prefer internal-sync-copilot-configs.py for all consumer alignment. -# This script is maintained for backward compatibility only. -# See .github/DEPRECATION.md for lifecycle policy. -``` -2. Record the deprecation in `.github/CHANGELOG.md`. -3. Update `copilot-quickstart.md` to recommend the sync script as the primary tool and the bootstrap script only as a legacy fallback. -4. Add the deprecation to `DEPRECATION.md` under "Current deprecations": -```markdown -## Current deprecations -- `scripts/bootstrap-copilot-config.sh`: Deprecated in favor of `scripts/internal-sync-copilot-configs.py`. Removal planned after all consumers migrate to sync-based alignment. -``` - ---- - -## Major Findings - -### M-01: No versioning or release strategy — consumers cannot pin to a known-good state - -**Files**: Repository root (missing `VERSION` file), `.github/CHANGELOG.md` (dates but no tags) - -The ANALYSIS_REPORT (item 2.1) flagged this as Major. It is still unresolved. Consumer repos have no way to pin to a specific standards version. If a breaking change is pushed to `main`, all consumers are immediately affected. - -**Fix**: -1. Create a `VERSION` file at the root with initial content: `1.0.0` -2. Add git tags at meaningful milestones (e.g., `v1.0.0` for the current stable state). -3. Update `internal-sync-copilot-configs.py` to include the source version in the manifest JSON. -4. Document the release process in a new `RELEASING.md` or in `CONTRIBUTING.md`. - ---- - -### M-02: No `CONTRIBUTING.md` — contributors have no documented process - -**File**: Missing — `CONTRIBUTING.md` - -This is a standards repository that other teams consume. Without contribution guidelines, team members (and Codex) have no reference for how to add new instructions, prompts, skills, or agents correctly. - -**Fix**: Create `CONTRIBUTING.md` with sections covering: -- How to add a new instruction file (naming, frontmatter, `applyTo`) -- How to add a new prompt (naming, frontmatter keys, skill reference) -- How to add a new skill (directory structure, SKILL.md template) -- How to add a new agent (naming, tools, restrictions) -- Naming conventions (origin-prefixed canonical names, `local-*` for consumer-local, `internal-*` for repo-owned assets) -- Required validation before PR (`make lint`, `make test`, and stack-specific checks) -- Required validation before PR (`make lint`, `make test`, and stack-specific checks) - ---- - -### M-03: No `Makefile` for developer workflow - -**File**: Missing — `Makefile` - -The ANALYSIS_REPORT (item 2.6) flagged this. It remains unresolved. Without a Makefile, developers and Codex must remember individual commands for linting, testing, and validation. - -**Fix**: Create `Makefile`: -```make -.PHONY: help lint validate test fmt all - -help: ## Show available targets - @grep -E '^[a-zA-Z_-]+:.*##' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*##"}; {printf " %-20s %s\n", $$1, $$2}' - -lint: ## Run shellcheck and bash syntax checks - bash -n .github/scripts/*.sh - shellcheck -s bash .github/scripts/*.sh - python3 -m compileall .github/scripts tests - -validate: ## Show repository validation guidance - @printf '%s\n' 'No repository-wide Copilot customization validator is configured.' - -test: ## Run Python test suite - pytest -q - -fmt: ## Format Terraform files - terraform fmt -recursive - -all: lint validate test ## Run all checks -``` - ---- - -### M-04: Repository validation guidance should stay aligned with the actual toolchain - -**Files**: `Makefile`, `CONTRIBUTING.md`, `AGENTS.md` - -The repository should document only the validation steps that actually exist. Stale references to removed validators create false expectations for contributors and automation. - -**Fix**: -1. Keep `make lint` and `make test` current with the real local checks. -2. Update repository documentation whenever validation steps are added or removed. -3. Avoid documenting repository-wide validators that no longer exist. - ---- - -### M-05: `dependabot.yml` still contains unused package ecosystems - -**File**: `.github/dependabot.yml` - -The ANALYSIS_REPORT (item 2.3) flagged this. Check if `npm`, `maven`, `gradle` ecosystems are still present. This repository only contains Bash, Python, and pre-commit hooks. Unused ecosystems waste CI minutes. - -**Fix**: Keep only the ecosystems relevant to this repo: `pip` (for pytest), `github-actions`, and optionally `terraform` (for pre-commit pin). Remove `npm`, `maven`, `gradle` if still present. If these ecosystems are intentionally kept as a template reference, move them to `templates/dependabot.template.yml` and document the intent. - ---- - -### M-06: No `docker.instructions.md` despite many consumer repos using Docker - -**File**: Missing — `.github/instructions/docker.instructions.md` - -The `AGENTS.md` has a backlog trigger: "Add `instructions/docker.instructions.md` when the first Dockerfile is introduced in this repository." But consumer repos likely already use Docker, and this standards repo should proactively provide Docker guidance regardless of whether *this* repo has Dockerfiles. - -**Fix**: Create `.github/instructions/docker.instructions.md`: -```instructions ---- -description: Docker and container build standards for secure, efficient, and reproducible images. -applyTo: "**/Dockerfile,**/Dockerfile.*,**/.dockerignore,**/docker-compose*.yml" ---- - -# Docker Instructions - -## Image build standards -- Use multi-stage builds to minimize image size. -- Run as non-root user. -- Use explicit base image tags with digests when possible. -- Keep `.dockerignore` up to date. -- Order layers for optimal cache usage (dependencies before source). - -## Security -- No secrets in build args, ENV, or COPY. -- Scan images for vulnerabilities in CI. -- Minimize installed packages. - -## Validation -- Build and test locally before pushing. -- Use health checks in orchestrated environments. -``` - -Also create a corresponding `prompts/internal-docker.prompt.md` and `skills/internal-docker/SKILL.md`. - ---- - -### M-07: `copilot-quickstart.md` still references bootstrap script as primary tool - -**File**: `.github/templates/copilot-quickstart.md` - -The quickstart guide's "Alignment strategy" section recommends `bootstrap-copilot-config.sh` first and `internal-sync-copilot-configs.py` second. Given C-01 (bootstrap deprecation), the order should be reversed and the bootstrap should be mentioned only as a legacy option. - -**Fix**: In the "Alignment strategy" section, change: -```markdown -## Alignment strategy -- Use `./.github/scripts/internal-sync-copilot-configs.sh --target --mode plan` for conservative alignment and minimum-asset selection (recommended). -- Use `.github/scripts/bootstrap-copilot-config.sh --target ` only as a legacy quick-copy fallback. -- Prefer canonical origin-prefixed script prompts in consumer repositories. -``` - ---- - -### M-08: `ANALYSIS_REPORT.md` is stale and some findings are already resolved - -**File**: `ANALYSIS_REPORT.md` - -The report is dated 2025-07-17 and references issues that have been fixed (e.g., prompt duplication consolidated, code-review instructions refactored, tests expanded from 5 to 27). Keeping the stale report creates confusion for Codex, which may attempt to fix already-resolved issues. - -**Fix**: Either: -1. Delete `ANALYSIS_REPORT.md` and replace with this `COPILOT_REVIEW.md` as the current audit. -2. Or add a clear header to `ANALYSIS_REPORT.md`: -```markdown -> **STATUS**: SUPERSEDED by `COPILOT_REVIEW.md` (2026-03-09). Many findings below have been resolved. -``` - ---- - -### M-09: Prompt `${input:...}` variable names are not standardized - -**Files**: All prompt files under `.github/prompts/` - -The ANALYSIS_REPORT (item 4.4) flagged inconsistent input variable naming. Prompts use various names for similar concepts: `target_file` vs `file_path` vs `target_path`, `description` vs `purpose` vs `feature_description`. - -**Fix**: -1. Define a canonical variable name catalog (add to `copilot-instructions.md` or a new `prompts/README.md`): - - `target_path`: the file or directory being acted upon - - `purpose`: what the deliverable should accomplish - - `language`: target programming language - - `test_framework`: testing framework to use - - `target_repo`: repository path for cross-repo operations -2. Audit all prompts and normalize variable names. -3. Add a validator check for canonical variable names. - ---- - -## Minor Findings - -### m-01: `agents/README.md` should reference repo-only agent exclusion - -**File**: `.github/agents/README.md` - -The agents README lists routing for all agents including repo-only ones (`internal-sync-global-copilot-configs-into-repo`), but does not explicitly mark them as non-syncable. This information is in `AGENTS.md` but should also be in the agents README for clarity. - -**Fix**: Add a note to the README: -```markdown -## Repo-only agents (not synced to consumers) -- `internal-sync-global-copilot-configs-into-repo` -- `internal-agent-sync` -``` - ---- - -### m-02: Pre-commit config missing `shellcheck` hook - -**File**: `.pre-commit-config.yaml` - -The ANALYSIS_REPORT (item 5.2) flagged this. The CI installs shellcheck but developers don't get local feedback. - -**Fix**: Add to `.pre-commit-config.yaml`: -```yaml -- repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.10.0.1 - hooks: - - id: shellcheck - args: ["-s", "bash"] -``` - ---- - -### m-03: `requirements-dev.txt` pins only `pytest` — add type checking - -**File**: `.github/requirements-dev.txt` - -Currently only `pytest==8.3.3`. The 2300-line sync script and 1200-line validator would benefit from type-checking support. - -**Fix**: Add `mypy` or at minimum `pyright`/`pylint` for static analysis: -``` -pytest==8.3.3 -mypy==1.14.1 -``` -Also consider adding `ruff` for linting Python scripts. - ---- - -### m-04: No architecture diagram for the customization framework - -**File**: Missing - -The ANALYSIS_REPORT (item 7.2) recommended a Mermaid diagram. The framework's hierarchy (instructions → prompts → skills → agents) plus the sync/validate pipeline deserves visual documentation. - -**Fix**: Add a Mermaid diagram to `.github/README.md`: -```markdown -## Architecture - -```mermaid -graph TD - A[copilot-instructions.md] --> B[instructions/*.instructions.md] - B --> C[prompts/*.prompt.md] - C --> D[skills/*/SKILL.md] - D --> E[agents/*.agent.md] - - F[AGENTS.md] --> A - F --> E - - G[make lint and make test] --> A - G --> B - G --> C - G --> D - G --> E - - H[internal-sync-copilot-configs.py] -->|plan/apply| I[Consumer Repos] - I --> J[Consumer AGENTS.md] -``` -``` - ---- - -### m-05: `security-baseline.md` controls lack enforcement coverage tracking - -**File**: `.github/security-baseline.md` - -The ANALYSIS_REPORT (item 5.1) flagged partial enforcement. The security baseline lists 11 controls but only ~4 are automated: - -| Control | Automated? | -|---------|-----------| -| SHA pinning | Yes (validator) | -| Minimal permissions | No | -| OIDC over secrets | No | -| Branch protection | No | -| Validate `.github/**` in CI | Yes (workflow) | -| shellcheck on scripts | Yes (CI) | -| No embedded secrets in prompts | Partial (pre-commit) | -| Deterministic prompt output | No | -| Read-only agents default | No | -| Scoped write agents | No | -| Change governance via CHANGELOG | No | - -**Fix**: Add an "Enforcement status" section to `security-baseline.md`: -```markdown -## Enforcement status -| Control | Status | Tool | -|---------|--------|------| -| SHA pinning | Manual review | — | -| Minimal permissions | Manual review | — | -| OIDC over secrets | Manual review | — | -| ... -``` - ---- - -### m-06: `AGENTS.md` "Preferred prompts" and "Preferred skills" have token-wasteful descriptions - -**File**: `AGENTS.md`, "Repository Defaults" section - -Each preferred prompt/skill includes a one-line description. These descriptions are already available in each prompt/skill's frontmatter `description:` field. Loading them here wastes tokens. - -**Fix**: Reduce to just the name, and let Codex resolve the description from the frontmatter: -```markdown -### Preferred prompts -- `internal-code-review` -- `internal-github-action` -- `internal-sync-global-copilot-configs-into-repo` -- `internal-pr-editor` -- `internal-add-unit-tests` -- `internal-terraform` -``` - -Or keep descriptions only for prompts where the name is ambiguous. - ---- - -### m-07: `CODEOWNERS` scope is narrow — bus factor of 2 - -**File**: `CODEOWNERS` - -Only `@pagopa/engineering-cloud @GNuccio96` own all files. For a repository that impacts all consumer repos, this is a single-point-of-failure risk. - -**Fix**: Consider adding a dedicated team like `@pagopa/copilot-standards` with at least 3-4 members. At minimum, add a backup reviewer. - ---- - -### m-08: No secret scanning tool in CI - -**File**: `.github/workflows/github-validate-copilot-customizations.yml` - -Pre-commit has `detect-private-key` but there's no CI-level secret scanning (e.g., `gitleaks`, `trufflehog`). - -**Fix**: Add a gitleaks step to the CI workflow: -```yaml -- name: Run gitleaks - uses: gitleaks/gitleaks-action@ # - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -``` - ---- - -### m-09: `internal-sync-copilot-configs.py` — `PROMPT_NAME_OVERRIDES` is a maintenance burden - -**File**: `.github/scripts/internal-sync-copilot-configs.py`, `PROMPT_NAME_OVERRIDES` dict - -This dict maps prompt filenames to legacy canonical name values. Every new prompt with a non-obvious name mapping needs a manual entry. This is fragile. - -**Fix**: Consider deriving the canonical name from the filename automatically using a naming convention function, and only using overrides for genuinely irregular cases. Or add a comment explaining the naming derivation rule and when an override is needed. - ---- - -### m-10: `.bootstrap-ignore` is empty - -**Files**: `.github/.bootstrap-ignore` (both repos) - -The file exists but contains only comments. It is never effectively used. - -**Fix**: Either populate with sensible defaults: -``` -# Exclude source-only assets from bootstrap copies -templates/ -tests/ -ANALYSIS_REPORT.md -COPILOT_REVIEW.md -requirements-dev.txt -__pycache__/ -.pytest_cache/ -``` -Or remove the file if the bootstrap script is deprecated (per C-01). - ---- - -## Nit Findings - -### N-01: `copilot-instructions.md` repeated "(or `.github/...` in `.github` layout)" parentheticals - -**File**: `.github/copilot-instructions.md` - -The file has 7 instances of the parenthetical `(or .github/... in .github layout)`. While this supports portability, it creates token overhead for every Codex session. Since both this repo and all known consumers use the `.github` layout, consider removing the parentheticals. - -**Fix**: Remove the parenthetical layout references from `copilot-instructions.md` and instead add a single "Layout note" section at the top: -```markdown -## Layout -This repository uses `.github/` layout. All paths below are relative to `.github/` unless otherwise noted. -``` - ---- - -### N-02: `AGENTS.md` "Anti-patterns" section — good content but verbose - -**File**: `AGENTS.md`, "Anti-patterns" section - -Seven "Do not use X when..." bullets are excellent guidance but could be more token-efficient using a table format. - -**Fix**: Convert to table: -```markdown -### Anti-patterns -| Don't | Instead | -|-------|---------| -| Planning capability for trivial single-file changes | Implementation capability directly | -| Implementation capability for ambiguous scope | Planning capability first | -| Generic review capability for domain-specific changes | Use matching specialist | -| ... -``` - ---- - -### N-03: Sync script `SOURCE_ONLY_AGENT_PATHS` should include the deprecated customization-auditor alias - -**File**: `.github/scripts/internal-sync-copilot-configs.py` - -The deprecated customization-auditor alias is in `SOURCE_ONLY_AGENT_PATHS`. Good. But verify the deprecated alias is also in the `AGENTS.md` inventory with a deprecation note. The current inventory lists it without a deprecation marker. - -**Fix**: Deprecated aliases for removed agents should also be cleaned up from inventory. - ---- - -### N-04: `CHANGELOG.md` entry dates — verify accuracy - -**File**: `.github/CHANGELOG.md` - -Entries are dated 2026-02-07 through 2026-03-08. Current date is 2026-03-09. The dates appear correct but double-check no entries have future dates or wrong ordering. - -**Fix**: No action needed if dates are accurate. - ---- - -### N-05: Skill files lack `dependencies:` frontmatter - -**File**: All `skills/*/SKILL.md` files - -The ANALYSIS_REPORT (item 4.1) recommended a `dependencies:` frontmatter field for machine-readable references. Skills reference instructions and other skills only in prose. - -**Fix**: Long-term improvement. Add `dependencies:` to skill frontmatter: -```yaml ---- -name: internal-terraform -description: ... -dependencies: - - instructions/terraform.instructions.md ---- -``` -This enables automated dependency validation. - ---- - -### N-06: `github-actions.instructions.md` checkout SHA example is outdated - -**File**: `.github/instructions/github-actions.instructions.md` - -The minimal example shows: -```yaml -uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.7 -``` - -But the CI workflow itself uses `v6.0.2`. The example should match the current recommended version. - -**Fix**: Update the example SHA and version to match the latest pinned version used in CI workflows. - ---- - -### N-07: `copilot-quickstart.md` suggested starter sets use instruction-only references - -**File**: `.github/templates/copilot-quickstart.md` - -The "Suggested starter sets" section recommends instructions + prompts + skills but doesn't mention agents. Consumer repos also need agent files for effective Copilot usage. - -**Fix**: Add agent recommendations to each starter set: -```markdown -- Java repositories: `java.instructions.md`, `internal-java.prompt.md`, `internal-project-java/SKILL.md`, plus planning, implementation, and review capabilities -``` - ---- - -## Architecture & Token Optimization - -These are strategic recommendations to maximize Codex's context window efficiency: - -### T-01: Flatten redundant content across `copilot-instructions.md` ↔ `AGENTS.md` - -**Current state**: Both files repeat prohibitions, validation baseline, and portability notes. -**Recommendation**: `AGENTS.md` should be the single source for repo-specific routing and inventory. `copilot-instructions.md` should contain only cross-cutting behavioral rules. Remove all duplicated content from `AGENTS.md` that's already in `copilot-instructions.md`. - -### T-02: Consider a slim `AGENTS.md` template for consumer repos - -**Current state**: The generated `AGENTS.md` for consumers is ~160 lines with full routing, prohibitions, and inventory. -**Recommendation**: The `AGENTS.template.md` is already slim. Ensure the sync script generates AGENTS.md content closer to the template length (~50-60 lines) rather than the current ~160 lines. Every line costs Codex tokens on every session. - -### T-03: Skill `SKILL.md` files should have a standardized "When to use" frontmatter field - -**Current state**: Skills explain when to use them in prose body, wasting tokens for discovery. -**Recommendation**: Add `when:` frontmatter for quick matching: -```yaml ---- -name: internal-terraform -description: Add or modify Terraform resources -when: Creating or modifying .tf files with resource, variable, output, or data blocks ---- -``` - ---- - -## Missing Assets & Gaps - -| Asset | Reason | Priority | -|-------|--------|----------| -| `CONTRIBUTING.md` | No contribution process documented | High | -| `Makefile` | No standardized developer commands | High | -| `VERSION` file | No versioning for consumer pinning | High | -| `instructions/docker.instructions.md` | Consumer repos use Docker | Medium | -| `prompts/internal-docker.prompt.md` | Pair with Docker instructions | Medium | -| `skills/internal-docker/SKILL.md` | Docker skill reference | Medium | -| Architecture Mermaid diagram | Visual aid for framework understanding | Medium | -| `instructions/sql.instructions.md` | DB migration safety | Low | -| `instructions/observability.instructions.md` | Cross-cutting logging standards | Low | - ---- - -## Action Checklist - -Ordered by impact on Codex effectiveness across all consumer repos: - -### Phase 1 — Immediate (highest Codex impact) -- [ ] **C-01**: Deprecate `bootstrap-copilot-config.sh` and update `DEPRECATION.md` -- [ ] **M-01**: Implement versioning strategy (`VERSION` file + git tags) -- [ ] **M-02**: Create `CONTRIBUTING.md` -- [ ] **M-03**: Create `Makefile` -- [ ] **M-08**: Archive or supersede stale `ANALYSIS_REPORT.md` -- [ ] **N-01**: Remove repeated layout parentheticals from `copilot-instructions.md` - -### Phase 2 — Short term (quality & safety) -- [ ] **M-04**: Expand validator test coverage to 15+ tests -- [ ] **M-05**: Clean up `dependabot.yml` unused ecosystems -- [ ] **M-06**: Create `docker.instructions.md` + prompt + skill -- [ ] **M-07**: Fix `copilot-quickstart.md` tool recommendations -- [ ] **m-02**: Add shellcheck to pre-commit -- [ ] **m-05**: Add enforcement status to `security-baseline.md` -- [ ] **m-08**: Add gitleaks to CI - -### Phase 3 — Medium term (polish & optimization) -- [ ] **M-09**: Standardize prompt `${input:...}` variable names -- [ ] **m-01**: Add repo-only agent exclusion note to agents README -- [ ] **m-03**: Add mypy/ruff to dev requirements -- [ ] **m-04**: Create architecture Mermaid diagram -- [ ] **m-06**: Reduce AGENTS.md preferred prompts/skills verbosity -- [ ] **m-07**: Expand CODEOWNERS team -- [ ] **m-09**: Simplify PROMPT_NAME_OVERRIDES -- [ ] **m-10**: Populate or remove `.bootstrap-ignore` - -### Phase 4 — Long term (strategic) -- [ ] **N-02**: Convert AGENTS.md anti-patterns to table -- [ ] **N-03**: Annotate deprecated agents in inventory -- [ ] **N-05**: Add `dependencies:` frontmatter to skills -- [ ] **N-06**: Update github-actions instruction example SHA -- [ ] **N-07**: Add agent recommendations to quickstart starter sets -- [ ] **T-01**: Flatten redundant content between copilot-instructions.md and AGENTS.md -- [ ] **T-02**: Optimize generated AGENTS.md length for consumers -- [ ] **T-03**: Add `when:` frontmatter to skills diff --git a/INTERNAL_CONTRACT.md b/INTERNAL_CONTRACT.md index 596eb39..3ae993f 100644 --- a/INTERNAL_CONTRACT.md +++ b/INTERNAL_CONTRACT.md @@ -65,7 +65,7 @@ Treat the current instruction architecture as the source of truth. Do not infer - Scope: - root `AGENTS.md` - `.github/copilot-instructions.md` - - scoped instructions, prompts, skills, and agents + - scoped instructions, skills, and agents - Expected behavior: - root `AGENTS.md` states that the default authoring language for repository artifacts is English unless a scoped instruction explicitly overrides it - `.github/copilot-instructions.md` may project that rule in compact form for Copilot flows @@ -124,7 +124,6 @@ Treat the current instruction architecture as the source of truth. Do not infer - Goal: ensure repository resources follow the naming convention defined by origin. - Scope: - - prompts - skills - agents - instructions @@ -137,12 +136,11 @@ Treat the current instruction architecture as the source of truth. Do not infer - Goal: ensure repository-owned resources that support explicit naming metadata declare it correctly. - Scope: - - internal prompts - internal skills - internal agents - Expected behavior: - every repository-owned internal resource has a non-empty canonical identifier - - every internal prompt, skill, and agent declares a non-empty `name:` + - every internal skill and agent declares a non-empty `name:` - every declared `name:` matches the canonical resource identifier - imported non-`internal-*` resources may remain verbatim @@ -200,6 +198,20 @@ Treat the current instruction architecture as the source of truth. Do not infer - the contract stays projected where Copilot or governance flows rely on it - root `AGENTS.md` may point to the repo-wide projection but does not need to carry the full formatting contract +#### `reporting-retained-learning-ledger-stays-governed` + +- Goal: preserve retained learning without turning it into shadow policy. +- Scope: + - root `AGENTS.md` + - `.github/copilot-instructions.md` + - `LESSONS.md` +- Expected behavior: + - repository-root `LESSONS.md` exists as a non-canonical learning ledger + - completed tasks add only durable, reusable lessons that were not already codified when discovered + - durable corrections to repeated or consequential misapplication of existing repository rules may also be retained as lessons + - no ledger update is required when no stable new lesson emerged + - once a lesson is codified elsewhere, it is removed from `LESSONS.md` instead of being retained as a codified duplicate + ### Future Automation Constraints #### `future-automation-reads-canonical-ownership` diff --git a/LESSONS.md b/LESSONS.md new file mode 100644 index 0000000..8e2f357 --- /dev/null +++ b/LESSONS.md @@ -0,0 +1,23 @@ +# Lessons + +This file retains durable lessons discovered while completing tasks in this repository. It is a learning ledger, not the canonical policy source. + +## Entry Rules + +- Before editing this file, read its current on-disk contents and treat them as the source of truth for in-progress local lessons, including local uncommitted rows already present on disk. +- Record only lessons that were not already codified in repository resources at the time they were learned. +- Also record durable corrections to repeated or consequential misapplication of already-codified repository rules when that correction is likely to prevent future mistakes. +- Keep only stable, reusable, repository-relevant lessons. +- Exclude secrets, transient debugging notes, raw conversation logs, and task-local noise. +- Keep new or still-uncodified lessons in the pending table until they are codified or deliberately dropped. +- Add a new lesson by appending one new row to the pending table; do not regenerate, reorder, or rewrite unrelated rows. +- Preserve unrelated existing lessons, including local uncommitted ones already on disk. +- Only update or remove a specific lesson row when that same lesson is being codified, disproven, narrowed, or deduplicated. + +## Pending Rules + +| Date | Lesson | Status | Intended canonical target | +| --- | --- | --- | --- | +| 2026-04-12 | For repo-owned standards work that deepens parallel skill sets, split planning into staged working documents under `tmp/superpowers/`, make anti-scope explicit, and sequence in-place parity work (`Common mistakes`, `Validation`, existing reference depth) before optional new skills, validators, or shared assets. | Pending | .github/copilot-instructions.md | +| 2026-04-12 | For provider-specific cloud skills, keep guidance provider-native and omit cross-cloud comparison or cloud-selection content when provider choice is already upstream of skill activation. | Pending | .github/copilot-instructions.md | +| 2026-04-12 | In source-of-truth guidance repositories, judge new GitHub Actions depth against downstream reuse needs, but keep auto-loaded instructions lean and move advanced patterns into skill references. | Pending | .github/copilot-instructions.md | diff --git a/README.md b/README.md new file mode 100644 index 0000000..9fec705 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# cloud-strategy.github + +Source repository for reusable GitHub Copilot governance and customization assets. + +- Start with [AGENTS.md](AGENTS.md) for the repository-wide bridge and precedence model. +- Use [.github/README.md](.github/README.md) for catalog orientation. +- Use [.github/INVENTORY.md](.github/INVENTORY.md) for the exact live catalog. diff --git a/tests/github/scripts/lib/test_fingerprinting.py b/tests/github/scripts/lib/test_fingerprinting.py new file mode 100644 index 0000000..13b8f38 --- /dev/null +++ b/tests/github/scripts/lib/test_fingerprinting.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +import json +from pathlib import Path + +from lib.fingerprinting import (build_fingerprint, build_manifest, + collect_files, diff_manifests, load_manifest, + normalize_content, render_diff_text) + + +def write_file(path: Path, content: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + + +def test_collect_files_expands_directories_and_builds_manifest(tmp_path: Path) -> None: + root = tmp_path + write_file(root / ".github/agents/internal-fast.agent.md", "# fast\n") + write_file(root / "README.md", "# readme\n") + + files = collect_files(root, [Path(".github/agents"), Path("README.md")]) + manifest = build_manifest( + root, files, source_ref_base="https://example.test/source" + ) + resources = { + resource["resource_id"]: resource for resource in manifest["resources"] + } + + assert [path.relative_to(root).as_posix() for path in files] == [ + ".github/agents/internal-fast.agent.md", + "README.md", + ] + assert resources[".github/agents/internal-fast.agent.md"]["kind"] == "agent" + assert resources[".github/agents/internal-fast.agent.md"]["source_ref"] == ( + "https://example.test/source/.github/agents/internal-fast.agent.md" + ) + + +def test_build_fingerprint_normalizes_text_and_leaves_binary_content_unchanged( + tmp_path: Path, +) -> None: + root = tmp_path + text_path = root / ".github/instructions/internal-python.instructions.md" + text_path.parent.mkdir(parents=True, exist_ok=True) + text_path.write_bytes(b"line one\r\nline two\r\n\r\n") + + fingerprint = build_fingerprint(root, text_path, source_ref_base="source-root") + + assert fingerprint.kind == "instruction" + assert ( + fingerprint.source_ref + == "source-root/.github/instructions/internal-python.instructions.md" + ) + assert fingerprint.metadata["bytes"] == len(b"line one\r\nline two\r\n\r\n") + assert fingerprint.metadata["normalized_bytes"] == len(b"line one\nline two\n") + assert normalize_content("binary.bin", b"\xff\x00") == b"\xff\x00" + + +def test_diff_manifests_tracks_changed_noise_only_created_and_removed( + tmp_path: Path, +) -> None: + old_manifest = { + "normalization_version": "v1", + "hash_algo": "sha256", + "resources": [ + {"resource_id": "same.md", "source_hash": "a", "content_hash": "same"}, + {"resource_id": "noise.md", "source_hash": "old", "content_hash": "same"}, + {"resource_id": "changed.md", "source_hash": "old", "content_hash": "old"}, + { + "resource_id": "removed.md", + "source_hash": "gone", + "content_hash": "gone", + }, + ], + } + new_manifest = { + "normalization_version": "v1", + "hash_algo": "sha256", + "resources": [ + {"resource_id": "same.md", "source_hash": "a", "content_hash": "same"}, + {"resource_id": "noise.md", "source_hash": "new", "content_hash": "same"}, + {"resource_id": "changed.md", "source_hash": "new", "content_hash": "new"}, + {"resource_id": "created.md", "source_hash": "new", "content_hash": "new"}, + ], + } + + result = diff_manifests(old_manifest, new_manifest) + diff_text = render_diff_text(result) + manifest_path = tmp_path / "manifest.json" + manifest_path.write_text(json.dumps(new_manifest), encoding="utf-8") + + assert result["summary"] == { + "created": 1, + "removed": 1, + "changed": 1, + "noise_only": 1, + "unchanged": 1, + } + assert "created created.md" in diff_text + assert "changed changed.md" in diff_text + assert load_manifest(manifest_path) == new_manifest diff --git a/tests/github/scripts/lib/test_internal_skills.py b/tests/github/scripts/lib/test_internal_skills.py new file mode 100644 index 0000000..99a9ff9 --- /dev/null +++ b/tests/github/scripts/lib/test_internal_skills.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +from pathlib import Path + +from lib.internal_skills import (detect_internal_skill_findings, + markdown_targets, resolve_reference, + validate_internal_skill) + + +def write_file(path: Path, content: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + + +def write_valid_skill(skill_dir: Path, skill_name: str) -> None: + write_file( + skill_dir / "SKILL.md", + "---\n" + f"name: {skill_name}\n" + "description: Keep repository-owned Python skills well shaped.\n" + "---\n\n" + f"# {skill_name}\n\n" + "Use `.github/copilot-sync.manifest.json` only as a generated artifact.\n" + "Reference `references/guide.md` for examples.\n" + "```md\n" + "[Ignored](references/missing.md)\n" + "```\n", + ) + write_file(skill_dir / "references/guide.md", "# guide\n") + write_file( + skill_dir / "agents/openai.yaml", + "interface:\n" + f" display_name: {skill_name}\n" + " short_description: Keep repository-owned Python skills aligned\n" + f" default_prompt: Use ${skill_name} for validation.\n", + ) + + +def test_detect_internal_skill_findings_filters_selected_skills( + tmp_path: Path, +) -> None: + root = tmp_path + (root / ".github").mkdir(parents=True, exist_ok=True) + write_valid_skill(root / ".github/skills/internal-good", "internal-good") + (root / ".github/skills/internal-bad").mkdir(parents=True, exist_ok=True) + + selected_findings = detect_internal_skill_findings( + root, selected_skills={"internal-good"} + ) + all_findings = detect_internal_skill_findings(root) + all_codes = {finding.code for finding in all_findings} + + assert selected_findings == [] + assert "missing-skill-md" in all_codes + + +def test_validate_internal_skill_reports_metadata_and_reference_issues( + tmp_path: Path, +) -> None: + root = tmp_path + (root / ".github").mkdir(parents=True, exist_ok=True) + skill_dir = root / ".github/skills/internal-demo" + write_file( + skill_dir / "SKILL.md", + "---\n" + "name: internal-other\n" + "description: Validate metadata for internal skills carefully.\n" + "---\n\n" + "# internal-demo\n\n" + "[Missing](references/missing.md)\n\n" + "```md\n" + "[Ignored](references/ignored.md)\n" + "```\n", + ) + write_file( + skill_dir / "agents/openai.yaml", + "interface:\n" + " display_name: Demo Skill\n" + " short_description: Too short\n" + " default_prompt: Use the validator.\n", + ) + + findings = validate_internal_skill(root, skill_dir) + finding_codes = {finding.code for finding in findings} + missing_reference_findings = [ + finding for finding in findings if finding.code == "missing-local-reference" + ] + + assert "skill-name-mismatch" in finding_codes + assert "short-description-length" in finding_codes + assert "default-prompt-skill-mention" in finding_codes + assert len(missing_reference_findings) == 1 + + +def test_markdown_targets_and_resolve_reference_support_repo_and_skill_paths( + tmp_path: Path, +) -> None: + root = tmp_path + skill_dir = root / ".github/skills/internal-demo" + source_file = skill_dir / "SKILL.md" + write_file(root / ".github/copilot-instructions.md", "# Copilot\n") + write_file(skill_dir / "references/example.md", "# Example\n") + text = ( + "[Repo](.github/copilot-instructions.md)\n" + "[Local](references/example.md)\n" + "`scripts/run.py`\n" + "`tmp/generated.md`\n" + ) + + targets = markdown_targets(text) + + assert ".github/copilot-instructions.md" in targets + assert "references/example.md" in targets + assert "scripts/run.py" in targets + assert ( + resolve_reference( + root, skill_dir, source_file, ".github/copilot-instructions.md" + ) + == root / ".github/copilot-instructions.md" + ) + assert resolve_reference(root, skill_dir, source_file, "references/example.md") == ( + skill_dir / "references/example.md" + ) + assert resolve_reference(root, skill_dir, source_file, "tmp/generated.md") is None + assert ( + resolve_reference(root, skill_dir, source_file, "https://example.com") is None + ) diff --git a/tests/github/scripts/lib/test_shared.py b/tests/github/scripts/lib/test_shared.py new file mode 100644 index 0000000..0d031e3 --- /dev/null +++ b/tests/github/scripts/lib/test_shared.py @@ -0,0 +1,108 @@ +from __future__ import annotations + +from pathlib import Path + +import pytest +from lib.shared import (Finding, all_files_under, dedupe_preserve_order, + find_repo_root, finding_sort_key, + is_consumer_sync_excluded_path, is_local_asset, + path_list, resolve_markdown_target, split_frontmatter, + strip_frontmatter) + + +def write_file(path: Path, content: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + + +def test_split_frontmatter_and_strip_frontmatter_return_expected_parts() -> None: + text = "---\nname: demo\nitems:\n - one\n---\nBody\n" + + frontmatter, body = split_frontmatter(text) + + assert frontmatter == {"name": "demo", "items": ["one"]} + assert body == "Body\n" + assert strip_frontmatter(text) == "Body\n" + + +def test_split_frontmatter_returns_empty_mapping_for_invalid_yaml() -> None: + text = "---\nname: [broken\n---\nBody\n" + + frontmatter, body = split_frontmatter(text) + + assert frontmatter == {} + assert body == "Body\n" + + +@pytest.mark.parametrize( + ("relative_path", "is_local", "is_excluded"), + [ + (".github/agents/local-helper.agent.md", True, False), + (".github/skills/local-demo/SKILL.md", True, False), + (".github/agents/internal-sync-helper.agent.md", False, True), + (".github/skills/internal-demo/agents/internal-sync-helper.yaml", False, True), + ("docs/readme.md", False, False), + ], +) +def test_local_and_consumer_excluded_path_helpers( + relative_path: str, is_local: bool, is_excluded: bool +) -> None: + assert is_local_asset(relative_path) is is_local + assert is_consumer_sync_excluded_path(relative_path) is is_excluded + + +def test_find_repo_root_and_resolve_markdown_target(tmp_path: Path) -> None: + root = tmp_path + current_file = root / ".github/agents/internal-router.agent.md" + (root / ".github/agents").mkdir(parents=True, exist_ok=True) + (root / "docs").mkdir(parents=True, exist_ok=True) + current_file.write_text("# router\n", encoding="utf-8") + + assert find_repo_root(root / "nested" / "deeper") == root + assert ( + resolve_markdown_target(root, current_file, "AGENTS.md") == root / "AGENTS.md" + ) + assert ( + resolve_markdown_target(root, current_file, ".github/copilot-instructions.md") + == root / ".github/copilot-instructions.md" + ) + assert ( + resolve_markdown_target(root, current_file, "../README.md#usage") + == (root / ".github/README.md").resolve() + ) + assert resolve_markdown_target(root, current_file, "https://example.com") is None + assert resolve_markdown_target(root, current_file, "/absolute/path.md") is None + + +def test_all_files_under_path_list_and_dedupe_preserve_order(tmp_path: Path) -> None: + root = tmp_path + write_file(root / ".github/agents/internal-fast.agent.md", "# fast\n") + write_file(root / ".github/agents/README.md", "# ignored\n") + write_file(root / ".github/agents/__pycache__/cache.pyc", "") + write_file(root / ".github/agents/local-helper.agent.md", "# local\n") + + assert all_files_under(root, ".github/agents") == [ + ".github/agents/internal-fast.agent.md", + ".github/agents/local-helper.agent.md", + ] + assert path_list(root, ".github/agents/*.agent.md") == [ + ".github/agents/internal-fast.agent.md", + ".github/agents/local-helper.agent.md", + ] + assert dedupe_preserve_order(["one", "two", "one", "three", "two"]) == [ + "one", + "two", + "three", + ] + + +def test_finding_sort_key_orders_blocking_findings_before_non_blocking() -> None: + findings = [ + Finding("non-blocking", "z-code", "b.md", "message", "suggestion"), + Finding("blocking", "a-code", "a.md", "message", "suggestion"), + ] + + ordered = sorted(findings, key=finding_sort_key) + + assert ordered[0].severity == "blocking" + assert ordered[0].path == "a.md" diff --git a/tests/github/scripts/test_cli_entrypoints.py b/tests/github/scripts/test_cli_entrypoints.py new file mode 100644 index 0000000..15d9fb3 --- /dev/null +++ b/tests/github/scripts/test_cli_entrypoints.py @@ -0,0 +1,259 @@ +from __future__ import annotations + +import argparse +import json +from pathlib import Path + +import audit_copilot_catalog +import build_inventory +import check_catalog_consistency +import detect_token_risks +import sync_copilot_catalog +import validate_internal_skills + + +def write_file(path: Path, content: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + + +def initialize_governance_repo(root: Path, *, with_inventory: bool = True) -> None: + write_file( + root / "AGENTS.md", + "# AGENTS\n\n" + "- Use `.github/copilot-instructions.md`.\n" + "- Use `.github/INVENTORY.md`.\n", + ) + write_file( + root / ".github/copilot-instructions.md", + "# Copilot Instructions\n\n" "See `AGENTS.md` and `.github/INVENTORY.md`.\n", + ) + if with_inventory: + sync_inventory(root) + + +def sync_inventory(root: Path) -> None: + write_file( + root / ".github/INVENTORY.md", build_inventory.build_inventory_markdown(root) + ) + + +def write_valid_internal_skill(skill_dir: Path, skill_name: str) -> None: + write_file( + skill_dir / "SKILL.md", + "---\n" + f"name: {skill_name}\n" + "description: Validate repository-owned skill metadata safely.\n" + "---\n\n" + f"# {skill_name}\n\n" + "Use `AGENTS.md` for bridge context.\n", + ) + write_file( + skill_dir / "agents/openai.yaml", + "interface:\n" + f" display_name: {skill_name}\n" + " short_description: Validate internal skill metadata safely\n" + f" default_prompt: Use ${skill_name} for validation.\n", + ) + + +def test_build_inventory_main_rebuilds_inventory_file( + monkeypatch, tmp_path: Path, capsys +) -> None: + initialize_governance_repo(tmp_path, with_inventory=False) + monkeypatch.setattr( + build_inventory, + "parse_args", + lambda: argparse.Namespace(root=str(tmp_path), check=False), + ) + + exit_code = build_inventory.main() + + assert exit_code == 0 + assert (tmp_path / ".github/INVENTORY.md").read_text( + encoding="utf-8" + ) == build_inventory.build_inventory_markdown(tmp_path) + assert "Inventory rebuilt successfully." in capsys.readouterr().out + + +def test_build_inventory_main_check_detects_inventory_drift( + monkeypatch, tmp_path: Path, capsys +) -> None: + initialize_governance_repo(tmp_path) + write_file(tmp_path / ".github/INVENTORY.md", "# stale\n") + monkeypatch.setattr( + build_inventory, + "parse_args", + lambda: argparse.Namespace(root=str(tmp_path), check=True), + ) + + exit_code = build_inventory.main() + + assert exit_code == 1 + assert "Inventory drift detected." in capsys.readouterr().out + + +def test_check_catalog_consistency_main_emits_json_and_fails_on_blocking_findings( + monkeypatch, tmp_path: Path, capsys +) -> None: + initialize_governance_repo(tmp_path, with_inventory=False) + write_file( + tmp_path / ".github/agents/internal-empty.agent.md", + "---\nname: internal-empty\ntools: []\n---\n\n# Empty\n", + ) + sync_inventory(tmp_path) + monkeypatch.setattr( + check_catalog_consistency, + "parse_args", + lambda: argparse.Namespace( + root=str(tmp_path), + include_token_risks=False, + strict=False, + format="json", + ), + ) + + exit_code = check_catalog_consistency.main() + payload = json.loads(capsys.readouterr().out) + finding_codes = {item["code"] for item in payload} + + assert exit_code == 1 + assert "internal-agent-missing-tools" in finding_codes + + +def test_detect_token_risks_main_respects_strict_mode( + monkeypatch, tmp_path: Path, capsys +) -> None: + repeated_lines = "\n".join( + [ + "- Keep policy separate from inventory.", + "- Keep AGENTS.md strategic and stable.", + "- Keep .github/copilot-instructions.md as the projection layer.", + "- Keep .github/INVENTORY.md as the exact catalog.", + "- Preserve explicit precedence rules.", + "- Remove overlap instead of keeping compatibility copies.", + ] + ) + + write_file(tmp_path / "AGENTS.md", f"# AGENTS\n\n{repeated_lines}\n") + write_file( + tmp_path / ".github/copilot-instructions.md", + f"# Copilot\n\n{repeated_lines}\n", + ) + write_file(tmp_path / ".github/INVENTORY.md", "# Inventory\n") + monkeypatch.setattr( + detect_token_risks, + "parse_args", + lambda: argparse.Namespace(root=str(tmp_path), strict=True, format="json"), + ) + + exit_code = detect_token_risks.main() + payload = json.loads(capsys.readouterr().out) + finding_codes = {item["code"] for item in payload} + + assert exit_code == 1 + assert "bridge-overlap" in finding_codes + + +def test_audit_copilot_catalog_main_groups_blocking_findings( + monkeypatch, tmp_path: Path, capsys +) -> None: + initialize_governance_repo(tmp_path, with_inventory=False) + monkeypatch.setattr( + audit_copilot_catalog, + "parse_args", + lambda: argparse.Namespace(root=str(tmp_path), format="text"), + ) + + exit_code = audit_copilot_catalog.main() + output = capsys.readouterr().out + + assert exit_code == 1 + assert "BLOCKING" in output + assert ".github/INVENTORY.md" in output + + +def test_validate_internal_skills_main_honors_skill_selection( + monkeypatch, tmp_path: Path, capsys +) -> None: + initialize_governance_repo(tmp_path, with_inventory=False) + write_valid_internal_skill( + tmp_path / ".github/skills/internal-good", "internal-good" + ) + (tmp_path / ".github/skills/internal-bad").mkdir(parents=True, exist_ok=True) + monkeypatch.setattr( + validate_internal_skills, + "parse_args", + lambda: argparse.Namespace( + root=str(tmp_path), + skill=["internal-good"], + strict=True, + format="text", + ), + ) + + exit_code = validate_internal_skills.main() + + assert exit_code == 0 + assert "validation passed with no findings" in capsys.readouterr().out + + +def test_sync_copilot_catalog_plan_mode_outputs_json_and_creates_plan( + monkeypatch, tmp_path: Path, capsys +) -> None: + source_root = tmp_path / "source" + target_root = tmp_path / "target" + initialize_governance_repo(source_root) + initialize_governance_repo(target_root, with_inventory=False) + write_file( + source_root / ".github/agents/internal-fast.agent.md", + "---\nname: internal-fast\ntools: [read]\n---\n\n# Fast\n", + ) + sync_inventory(source_root) + monkeypatch.setattr( + sync_copilot_catalog, + "parse_args", + lambda: argparse.Namespace( + command="plan", + source_root=str(source_root), + target_repo=str(target_root), + allow_dirty_target=False, + format="json", + ), + ) + + exit_code = sync_copilot_catalog.main() + payload = json.loads(capsys.readouterr().out) + + assert exit_code == 0 + assert payload["mode"] == "plan" + assert payload["plan_path"].endswith("tmp/copilot-sync.plan.md") + assert (target_root / "tmp/copilot-sync.plan.md").exists() + + +def test_sync_copilot_catalog_apply_aborts_when_source_has_blocking_findings( + monkeypatch, tmp_path: Path, capsys +) -> None: + source_root = tmp_path / "source" + target_root = tmp_path / "target" + initialize_governance_repo(source_root, with_inventory=False) + initialize_governance_repo(target_root, with_inventory=False) + monkeypatch.setattr( + sync_copilot_catalog, + "parse_args", + lambda: argparse.Namespace( + command="apply", + source_root=str(source_root), + target_repo=str(target_root), + allow_dirty_target=False, + format="text", + ), + ) + + exit_code = sync_copilot_catalog.main() + + assert exit_code == 1 + assert not (target_root / ".github/copilot-sync.manifest.json").exists() + assert ( + "Source repository has blocking governance findings" in capsys.readouterr().out + ) diff --git a/tests/github/scripts/test_repo_owned_script_coverage.py b/tests/github/scripts/test_repo_owned_script_coverage.py new file mode 100644 index 0000000..4b596db --- /dev/null +++ b/tests/github/scripts/test_repo_owned_script_coverage.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from pathlib import Path + +TEST_OWNERS = { + "tests/github/scripts/test_cli_entrypoints.py": { + ".github/scripts/audit_copilot_catalog.py", + ".github/scripts/build_inventory.py", + ".github/scripts/check_catalog_consistency.py", + ".github/scripts/detect_token_risks.py", + ".github/scripts/sync_copilot_catalog.py", + ".github/scripts/validate_internal_skills.py", + }, + "tests/github/scripts/lib/test_fingerprinting.py": { + ".github/scripts/lib/fingerprinting.py", + }, + "tests/github/scripts/lib/test_internal_skills.py": { + ".github/scripts/lib/internal_skills.py", + }, + "tests/github/scripts/lib/test_shared.py": { + ".github/scripts/lib/shared.py", + }, + "tests/test_inventory_and_consistency.py": { + ".github/scripts/lib/catalog_checks.py", + ".github/scripts/lib/inventory.py", + }, + "tests/test_sync_and_token_risks.py": { + ".github/scripts/lib/syncing.py", + ".github/scripts/lib/token_risks.py", + }, +} + + +def test_all_repo_owned_python_scripts_have_declared_test_owners() -> None: + source_scripts = { + path.as_posix() + for path in Path(".github/scripts").rglob("*.py") + if ".venv" not in path.parts + and "__pycache__" not in path.parts + and path.name != "__init__.py" + } + declared_scripts = { + script_path + for covered_scripts in TEST_OWNERS.values() + for script_path in covered_scripts + } + + assert declared_scripts == source_scripts + assert all(Path(script_path).is_file() for script_path in declared_scripts) + assert all(Path(test_path).is_file() for test_path in TEST_OWNERS) diff --git a/tests/test_inventory_and_consistency.py b/tests/test_inventory_and_consistency.py index f2ff5af..03c6145 100644 --- a/tests/test_inventory_and_consistency.py +++ b/tests/test_inventory_and_consistency.py @@ -30,8 +30,6 @@ def test_build_inventory_markdown_lists_catalog_sections(tmp_path: Path) -> None assert "## Instructions" in inventory assert "- `.github/instructions/internal-python.instructions.md`" in inventory - assert "## Prompts" in inventory - assert "No prompt files currently ship in the live catalog." in inventory assert "- `.github/skills/internal-catalog/SKILL.md`" in inventory assert "- `.github/agents/internal-fast-executor.agent.md`" in inventory @@ -49,7 +47,7 @@ def test_run_consistency_checks_flags_inventory_drift_and_missing_tools( ) write_file( tmp_path / ".github/INVENTORY.md", - "# Copilot Inventory\n\n## Instructions\n\nNo instruction files currently ship in the live catalog.\n\n## Prompts\n\nNo prompt files currently ship in the live catalog.\n\n## Skills\n\nNo skill files currently ship in the live catalog.\n\n## Agents\n\nNo agent files currently ship in the live catalog.\n", + "# Copilot Inventory\n\n## Instructions\n\nNo instruction files currently ship in the live catalog.\n\n## Skills\n\nNo skill files currently ship in the live catalog.\n\n## Agents\n\nNo agent files currently ship in the live catalog.\n", ) write_file( tmp_path / ".github/agents/internal-sync.agent.md", diff --git a/tests/test_retained_learning_contract.py b/tests/test_retained_learning_contract.py new file mode 100644 index 0000000..83974d6 --- /dev/null +++ b/tests/test_retained_learning_contract.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent + + +def read_text(relative_path: str) -> str: + return (REPO_ROOT / relative_path).read_text(encoding="utf-8") + + +def test_retained_learning_contract_preserves_on_disk_lessons_rows() -> None: + expected_contracts: dict[str, list[str]] = { + "AGENTS.md": [ + "Keep `LESSONS.md` append-preserving by default", + "preserve unrelated rows already on disk, including local uncommitted lessons", + ( + "change a specific row only when that same lesson is being codified, " + "disproven, narrowed, or deduplicated" + ), + ], + ".github/copilot-instructions.md": [ + "Before editing repository-root `LESSONS.md`, read its current on-disk contents", + "including uncommitted rows already present on disk", + "append one concise, reusable row to the pending table in `LESSONS.md`", + "do not regenerate, reorder, or rewrite unrelated rows", + ( + "Preserve unrelated existing lessons in `LESSONS.md`, including local " + "uncommitted ones already on disk" + ), + "update or remove only that lesson's row before completion", + ], + "LESSONS.md": [ + "Before editing this file, read its current on-disk contents", + "including local uncommitted rows already present on disk", + ( + "Add a new lesson by appending one new row to the pending table; do not " + "regenerate, reorder, or rewrite unrelated rows." + ), + "Preserve unrelated existing lessons, including local uncommitted ones already on disk.", + ( + "Only update or remove a specific lesson row when that same lesson is being " + "codified, disproven, narrowed, or deduplicated." + ), + ], + } + + for relative_path, expected_snippets in expected_contracts.items(): + text = read_text(relative_path) + for snippet in expected_snippets: + assert ( + snippet in text + ), f"{relative_path} is missing retained-learning guardrail text: {snippet}" diff --git a/tests/test_sync_and_token_risks.py b/tests/test_sync_and_token_risks.py index 7679e2a..9fabc95 100644 --- a/tests/test_sync_and_token_risks.py +++ b/tests/test_sync_and_token_risks.py @@ -43,6 +43,10 @@ def test_build_sync_plan_preserves_local_assets_and_deletes_non_local_assets( target_root / ".github/agents/local-special.agent.md", "---\nname: local-special\ntools: [read]\n---\n", ) + write_file( + target_root / ".github/local-copilot-overrides.md", + "# Local Copilot Overrides\n\n- Override: Keep repo-local behavior explicit.\n", + ) write_file( target_root / ".github/agents/custom.agent.md", "---\nname: custom\ntools: [read]\n---\n", @@ -52,11 +56,35 @@ def test_build_sync_plan_preserves_local_assets_and_deletes_non_local_assets( actions = {(operation.action, operation.path) for operation in plan.operations} assert ("preserve", ".github/agents/local-special.agent.md") in actions + assert ("preserve", ".github/local-copilot-overrides.md") in actions assert ("delete", ".github/agents/custom.agent.md") in actions assert ("update", ".github/agents/internal-fast.agent.md") in actions assert ("delete", ".github/agents/internal-sync-legacy.agent.md") in actions +def test_build_sync_plan_does_not_mirror_source_local_override_file( + tmp_path: Path, +) -> None: + source_root = tmp_path / "source" + target_root = tmp_path / "target" + + write_file(source_root / "AGENTS.md", "# AGENTS\nsource\n") + write_file(source_root / ".github/copilot-instructions.md", "# Copilot\nsource\n") + write_file( + source_root / ".github/local-copilot-overrides.md", + "# Local Copilot Overrides\n\n- No active overrides in this repository.\n", + ) + write_file(target_root / "AGENTS.md", "# AGENTS\ntarget\n") + write_file(target_root / ".github/copilot-instructions.md", "# Copilot\ntarget\n") + + plan = build_sync_plan(source_root, target_root) + + assert all( + operation.path != ".github/local-copilot-overrides.md" + for operation in plan.operations + ) + + def test_apply_sync_plan_clears_plan_file_and_writes_manifest(tmp_path: Path) -> None: source_root = tmp_path / "source" target_root = tmp_path / "target" @@ -79,6 +107,10 @@ def test_apply_sync_plan_clears_plan_file_and_writes_manifest(tmp_path: Path) -> write_file( target_root / ".github/internal-sync-copilot-configs.manifest.json", "{}\n" ) + write_file( + target_root / ".github/local-copilot-overrides.md", + "# Local Copilot Overrides\n\n- Override: Keep target-local exceptions.\n", + ) plan = build_sync_plan(source_root, target_root) plan_path = write_sync_plan(plan) @@ -93,6 +125,7 @@ def test_apply_sync_plan_clears_plan_file_and_writes_manifest(tmp_path: Path) -> assert not ( target_root / ".github/internal-sync-copilot-configs.manifest.json" ).exists() + assert (target_root / ".github/local-copilot-overrides.md").exists() assert "AGENTS.md" in manifest["managed_hashes"] assert manifest["managed_hashes"][".github/agents/internal-fast.agent.md"] assert (target_root / "AGENTS.md").read_text( @@ -100,7 +133,7 @@ def test_apply_sync_plan_clears_plan_file_and_writes_manifest(tmp_path: Path) -> ) == "# AGENTS\nsource\n" assert (target_root / ".gitignore").read_text( encoding="utf-8" - ) == "/docs/superpowers/\n" + ) == "/tmp/superpowers/\n" def test_build_sync_plan_ensures_target_gitignore_entry_without_mirroring_source_gitignore( @@ -120,10 +153,10 @@ def test_build_sync_plan_ensures_target_gitignore_entry_without_mirroring_source operations = {(operation.action, operation.path) for operation in plan.operations} assert ("ensure", ".gitignore") in operations - assert plan.generated_gitignore == "node_modules/\n/docs/superpowers/\n" + assert plan.generated_gitignore == "node_modules/\n/tmp/superpowers/\n" -def test_build_sync_plan_accepts_existing_docs_superpowers_gitignore_entry( +def test_build_sync_plan_accepts_existing_tmp_superpowers_gitignore_entry( tmp_path: Path, ) -> None: source_root = tmp_path / "source" @@ -133,13 +166,13 @@ def test_build_sync_plan_accepts_existing_docs_superpowers_gitignore_entry( write_file(source_root / ".github/copilot-instructions.md", "# Copilot\nsource\n") write_file(target_root / "AGENTS.md", "# AGENTS\ntarget\n") write_file(target_root / ".github/copilot-instructions.md", "# Copilot\ntarget\n") - write_file(target_root / ".gitignore", "node_modules/\ndocs/superpowers/\n") + write_file(target_root / ".gitignore", "node_modules/\ntmp/superpowers/\n") plan = build_sync_plan(source_root, target_root) actions = {(operation.action, operation.path) for operation in plan.operations} assert ("unchanged", ".gitignore") in actions - assert plan.generated_gitignore == "node_modules/\ndocs/superpowers/\n" + assert plan.generated_gitignore == "node_modules/\ntmp/superpowers/\n" def test_detect_token_risks_reports_bridge_overlap(tmp_path: Path) -> None: @@ -167,6 +200,28 @@ def test_detect_token_risks_reports_bridge_overlap(tmp_path: Path) -> None: assert "bridge-overlap" in finding_codes +def test_detect_token_risks_ignores_structural_bridge_references( + tmp_path: Path, +) -> None: + write_file( + tmp_path / "AGENTS.md", + "# AGENTS\n\n" + "- Use `.github/copilot-instructions.md` as the repo-wide projection.\n" + "- Use `.github/INVENTORY.md` as the live catalog.\n" + "- Use `.github/instructions/` for scoped guidance.\n" + "- Use `.github/skills/` when a reusable workflow is relevant.\n" + "- Use `.github/agents/` when a stable owner is relevant.\n" + "- Keep `.github/local-copilot-overrides.md` local to consumer repositories.\n", + ) + write_file(tmp_path / ".github/copilot-instructions.md", "# Copilot\n") + write_file(tmp_path / ".github/INVENTORY.md", "# Inventory\n") + + findings = detect_token_risks(tmp_path) + finding_codes = {finding.code for finding in findings} + + assert "inventory-dump-in-bridge" not in finding_codes + + def test_detect_token_risks_reports_internal_root_policy_overlap( tmp_path: Path, ) -> None: