diff --git a/.agents/skills/adding-a-migration-step/SKILL.md b/.agents/skills/adding-a-migration-step/SKILL.md deleted file mode 100644 index 85a2e7307..000000000 --- a/.agents/skills/adding-a-migration-step/SKILL.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: adding-a-migration-step -description: How to make fallout-migrate handle a new rename, removal, or rewrite by extending an existing IMigrationStep, and when a genuinely new step is warranted. Trigger when asked to add a rename/rewrite rule to fallout-migrate, or to touch src/Fallout.Migrate/Migration.cs or its Steps. ---- - -`fallout-migrate` runs a fixed, ordered list of `IMigrationStep` implementations, -built in `src/Fallout.Migrate/Migration.cs`. A **step is one operation over one -set of files**, and it owns the rewrite rules for those files. -`RewriteCsprojsStep` holds the rules for `*.csproj`; `RewriteCsFilesStep` holds -the rules for `*.cs`. - -## Adding a new rename, removal, or rewrite - -1. Find the step for that file type — `RewriteCsprojsStep` for `*.csproj`, - `RewriteCsFilesStep` for `*.cs`, `RewriteBootstrapScriptsStep` for the - bootstrap scripts. -2. Add a `private static readonly Regex` field to that step, with a comment - saying what moved and why. -3. Apply it as another statement in the step's `Rewrite` method, incrementing - `edits` per replacement. -4. Add cases to that step's spec class in `tests/Fallout.Migrate.Specs`. - -**Do not add a step per rename.** A new step means a second pass over the same -files, so each file is written twice and the `Summary` edit count is inflated. -Rule order also matters — a specific rule usually has to run before a general -one — and inside one `Rewrite` method that order is plain statement order. -Split across steps it becomes a hidden dependency between entries in -`Migration.steps`. - -## When a new step actually is warranted - -Only for a new set of files or a genuinely different operation, such as -renaming a directory or prompting the user. That's one new class implementing -`IMigrationStep` plus one line in `Migration.steps`. If the new step depends on -an earlier one, say so in the comment on that list entry, the way -`ResolveFalloutVersionStep` does. - -Keep `Steps/` free of helper classes. A rewriter that only serves one step -belongs inside that step — see `aef6c073` (`CsprojRewriter`) and #528 -(`CodeRewriter`) for the shape. diff --git a/.agents/skills/adding-a-tool-wrapper/SKILL.md b/.agents/skills/adding-a-tool-wrapper/SKILL.md deleted file mode 100644 index c2938fd8b..000000000 --- a/.agents/skills/adding-a-tool-wrapper/SKILL.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: adding-a-tool-wrapper -description: Recipe for adding or extending a CLI tool wrapper under src/Fallout.Common/Tools//.json. Trigger when asked to add a new tool wrapper, add a command/argument to an existing one, or when a Tools/*.json file is being edited. ---- - -Tool wrapper `.json` files are the source of truth; the `.cs` next to each one -is generated — never hand-edit the generated file. - -1. Find the closest existing tool under `src/Fallout.Common/Tools//.json` - and copy its shape. -2. Cover a full command with all its arguments, not just the one option you need. -3. Use formatting tags in `help` text: - - `` for inline code - - `` for links - - `
    ` / `
      ` for lists - - `` for emphasized text - - `` between paragraphs (not `

      ...

      `) -4. Don't write `secret: false` — it's the default. -5. Don't write `default: xxx` — obsolete field, omit it. -6. Run `./build.ps1 GenerateTools` to regenerate the `.cs` output. -7. Commit the regenerated `.cs` alongside the `.json` spec in the same commit — - `VerifyGeneratedTools` fails CI if they drift. diff --git a/.agents/skills/creating-a-pr/SKILL.md b/.agents/skills/creating-a-pr/SKILL.md deleted file mode 100644 index a03efb5c1..000000000 --- a/.agents/skills/creating-a-pr/SKILL.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -name: creating-a-pr -description: Steps for opening a pull request in the Fallout repo — picking the right base branch, creating it as a draft, applying the target/vCurrent-or-vNext and changelog-category labels, and handling breaking changes. Trigger whenever you are about to run `gh pr create`, decide a branch/base, write commit messages, or write a PR/issue description. ---- - -Follow this exactly when opening a PR. Don't skip the labelling — it's easy to -drop because it's just flags on the same `gh pr create` call. - -## 0. Working from a fork? - -Check `git remote -v`. If it shows both `origin` (your fork) and `upstream` -(`Fallout-build/Fallout`), branch from `upstream/develop` — never -`origin/develop`, which can be far behind and cause needless conflicts: - -```bash -git fetch upstream develop -git switch -c upstream/develop -git push -u origin -gh pr create --repo Fallout-build/Fallout --draft ... -``` - -Skip this for a plain single-remote clone. - -## 1. Create as a draft - -**Every new PR starts as a draft** — `gh pr create --draft` — unless the user -explicitly asked for ready-for-review. Never omit `--draft` by default. - -## 2. Label at creation time, not as a follow-up - -- **`target/vCurrent`** (default) or **`target/vNext`** (breaking changes — see - below) — pass `--label target/vCurrent`. -- **One changelog-category label** from [`.github/release.yml`](../../../.github/release.yml): - `enhancement`, `bug`, `security`, `documentation`, `breaking-change`, or - `skip-changelog` for housekeeping. Don't leave a PR uncategorized — it falls - through to "Other Changes". - -## 3. Breaking change? Do all of this too - -A change is breaking if a commit uses the `!` suffix, has a `BREAKING CHANGE:` -footer, or a reviewer would reasonably flag it (renamed/removed public API, -package ID change, on-disk format change, CI/CD shape change consumers depend -on) — except changes to `[Experimental]` surface, which carries no guarantee. - -1. `--label target/vNext --label breaking-change` (use `breaking-change` - instead of `enhancement`/`bug` as the changelog category). -2. Open the PR body with a `⚠️ Breaking change` callout: name the affected - surface and the consumer-side impact in one sentence. -3. **Target `develop`**, never `release/vX.Y` or `main` — confirm the breaking - surface sits behind `[Experimental("FALLOUT0xx")]` (see the - `marking-experimental-apis` skill), or, if it can't be gated, on a - short-lived branch off `develop` held for the next major. Don't bump - `version.json`'s major — that happens once, at the cut. -4. Spell out the migration path (one paragraph minimum) — what a consumer - changes and what they run. There's no `CHANGELOG.md`; the `breaking-change` - label is what carries this into the generated release notes. - -If you only discover the breaking nature mid-review, apply all of this before -requesting re-review. - -## Writing the description - -Follow the [plain-english skill](../plain-english/SKILL.md) for the terse, -scannable shape (issues too) — lead with the point, bullets over prose, link -don't recap. - -## Full policy reference - -[references/pr-creation-flow.md](references/pr-creation-flow.md) has the -complete versioning-policy and milestone-labelling background behind the -steps above, if you need the "why". diff --git a/.agents/skills/creating-a-pr/references/pr-creation-flow.md b/.agents/skills/creating-a-pr/references/pr-creation-flow.md deleted file mode 100644 index 28074a083..000000000 --- a/.agents/skills/creating-a-pr/references/pr-creation-flow.md +++ /dev/null @@ -1,43 +0,0 @@ -# PR-creation flow — full policy background - -The step-by-step procedure lives in the parent [SKILL.md](../SKILL.md). This -file is the "why" behind it: the versioning policy a breaking-change PR must -satisfy, and how milestones map to the `target/*` labels. - -## Versioning policy - -This project ships classic semver ([ADR-0009](../../../../docs/adr/0009-gitflow-and-semver-reversion.md)). -The rule: **breaking changes wait for the next major**, and there's no fixed -date for that — the project stays on `10.x` for as long as it can, and the -eventual move to v11 will go through `fallout-migrate`. - -There is **no `CHANGELOG.md`** — the file was retired. Release notes are -generated from PR labels via [`.github/release.yml`](../../../../.github/release.yml). -The PR description and its labels are now the lasting record of a change. - -- A breaking change lands on **`develop`, behind `[Experimental("FALLOUT0xx")]`** - (or, if that doesn't fit, on a short-lived branch off `develop` held until - the cut). It does **not** bump `version.json`'s major mid-cycle. -- **A `release/vX.Y` or `main` production line never takes a breaking change.** - It only takes non-breaking work. The review before a production cut is the - backstop that keeps an ungated breaking change off the production line. -- Surface that isn't ready to commit to yet can ship behind - `[Experimental("FALLOUT0xx")]` instead of being held back — see the - `marking-experimental-apis` skill. - -**Reviewer responsibility:** if a PR carries `!` (or a flagged breaking -change), check that it targets `develop`, not a production branch. Check that -the breaking surface is behind `[Experimental("FALLOUT0xx")]` (or on a topic -branch, if it can't be gated). Check that the PR description has the -`⚠️ Breaking change` callout with a migration path. Block the PR if any of -that is missing. - -## Milestones and version targeting - -Milestones are **theme-based** (e.g. "Plugin Architecture Foundation & -Rebrand Completion", "Public Plugin SDK", "Continuous Delivery Vision") and -carry across releases; version targeting uses **evergreen `target/vCurrent` / -`target/vNext`** labels — `target/vCurrent` is the current release line, -`target/vNext` is the next major. A breaking change is held for the next -major, so its PR carries `target/vNext`. See [docs/roadmap.md](../../../../docs/roadmap.md) -for the current milestones. diff --git a/.agents/skills/cutting-a-release/SKILL.md b/.agents/skills/cutting-a-release/SKILL.md deleted file mode 100644 index 23cf8f0ea..000000000 --- a/.agents/skills/cutting-a-release/SKILL.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: cutting-a-release -description: Procedure for tagging, publishing, promoting, or cutting a new release/vX.Y branch, hotfixing a production line, or cutting the eventual v11 major. Trigger on requests to cut a release, publish to nuget.org, tag a version, hotfix main or support/v10, or promote a release branch to GA. ---- - -The maintainer runbook is [docs/branching-and-release.md](../../../docs/branching-and-release.md) -— read it and follow it exactly; this file is a quick index into it plus the -gotchas worth knowing before you start. - -## Which section of the runbook you need - -| You're asked to... | Read | -| --- | --- | -| Cut a new `release/vX.Y` and tag `-rc.N` builds | [Cutting a release](../../../docs/branching-and-release.md#cutting-a-release) | -| Publish a GA tag to nuget.org | [Publishing to nuget.org](../../../docs/branching-and-release.md#publishing-to-nugetorg) | -| Ship an emergency fix to `main` or `support/v10` | [Hotfixing production](../../../docs/branching-and-release.md#hotfixing-production) | -| Cut the eventual v11 | [Cutting v11](../../../docs/branching-and-release.md#cutting-v11-when-it-eventually-happens) | -| Retire an old `support/*` line | [Deprecating a support/* line](../../../docs/branching-and-release.md#deprecating-a-support-line) | -| First-ever publish of a new `Fallout.X` package | [First-publish gotcha](../../../docs/branching-and-release.md#adding-a-new-falloutx-package--first-publish-gotcha) | - -## Gotchas worth knowing up front - -- **`--ref` on `workflow_dispatch` must be the production branch**, not the - default branch — it runs *that ref's copy* of the workflow. -- **`--notes-start-tag` must be the last GA tag**, not the previous rc, or the - generated notes only cover since the last rc. -- **A green pipeline run is not proof anything published** — every publish job - is conditional. Verify job conclusions and the nuget.org index after a - release (commands in the runbook). -- **nuget.org is always opt-in** via `workflow_dispatch -f publish-to-nugetorg=true`; - a tag push alone only reaches GitHub Packages + GitHub Releases. -- Never bypass a hotfix through direct pushes — branch protection blocks it - everywhere; even a one-commit cherry-pick goes through a PR. diff --git a/.agents/skills/editing-ci-workflows/SKILL.md b/.agents/skills/editing-ci-workflows/SKILL.md deleted file mode 100644 index e1e42173e..000000000 --- a/.agents/skills/editing-ci-workflows/SKILL.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: editing-ci-workflows -description: Invariants to preserve when touching .github/workflows/**, build/Build.CI.GitHubActions.cs, or anything about which branches/tags trigger CI or publish packages. Trigger before editing a workflow YAML file, the CI generator source, or branch trigger lists. ---- - -Read [references/ci-invariants.md](references/ci-invariants.md) in full before -changing a workflow — most mistakes here are "looks fine, quietly breaks a -gating assumption." The short version: - -- **`build.yml` and `build-cross-platform.yml` are generated** from - `build/Build.CI.GitHubActions.cs` — edit the attributes/constants there and - regenerate (`./build.sh`), never hand-edit those two `.yml` files. - `build-skip.yml`, `publish-packages-preview.yml`, and - `publish-packages-release.yml` are hand-written; those you do edit directly. -- **Feature branches run zero CI** until a PR targets a long-lived branch - (`develop`/`main`/`release/*`/`support/*`). Never add a working-branch - pattern (`feature/*`, `bugfix/*`, …) to a push/PR trigger. -- **Cross-platform (`windows`/`macos`) is release-intent-gated** — PRs into - `main`/`release/*`/`support/*`, or a `v*` tag push. Never add `develop` to - its push triggers. -- **`concurrency: cancel-in-progress` everywhere except `publish-packages-release.yml`** - — never cancel a publish mid-flight. -- **Every publishing lane runs `Test` before it publishes**, as a single - `dotnet fallout Test Pack` invocation, not split steps — splitting - double-compiles. -- Don't add `submodules: recursive` to a checkout step — there are no - submodules in this repo. - -See also [docs/architecture.md](../../../docs/architecture.md#ci-layout) for -the current workflow-to-trigger table, and -[docs/branching-and-release.md](../../../docs/branching-and-release.md) for -the branch-protection rulesets these triggers back onto. diff --git a/.agents/skills/editing-ci-workflows/references/ci-invariants.md b/.agents/skills/editing-ci-workflows/references/ci-invariants.md deleted file mode 100644 index 2ab48917b..000000000 --- a/.agents/skills/editing-ci-workflows/references/ci-invariants.md +++ /dev/null @@ -1,49 +0,0 @@ -# CI pipeline & trigger invariants - -Shaped by [milestone #18](https://github.com/Fallout-build/Fallout/milestone/18) -and the branch model in [ADR-0009](../../../../docs/adr/0009-gitflow-and-semver-reversion.md) -(carrying forward [ADR-0008](../../../../docs/adr/0008-collapse-experimental-into-main.md), -which collapsed `experimental` into the integration trunk). - -- **Feature branches run zero CI until a PR is opened.** Push triggers list - **only** long-lived branches; nothing fires on `feature/*`, `bugfix/*`, etc. - until they're PR'd against `develop`/`main`/`release/*`/`support/*`. Do - **not** add a working-branch pattern to any `OnPush*`/`branches:` trigger. -- **The Linux PR gate (job `ubuntu-latest`, from `build.yml`) is the only - required check** — runs on PRs to the long-lived branches. (Branch - protection keys on the job name, not the workflow file.) -- **A push to `develop` publishes `-preview`** to GitHub Packages - (`publish-packages-preview.yml`). It's the only continuous publisher — - there is still no `experimental.yml`. -- **Cross-platform `windows`/`macos` only run on release intent** — one - `build-cross-platform.yml` workflow (a job per OS), firing on a PR into - `main`/`release/*`/`support/*`, or a `v*` tag push. They do **not** run on - `develop` pushes. `develop` relies on the Linux gate instead. -- **`concurrency: cancel-in-progress` on every build workflow except - `publish-packages-release.yml`** — never cancel a publish mid-flight. -- **Canonical CI-ignore paths:** `docs/**`, `.assets/**`, `**/*.md` — applied - to every PR/push trigger. -- The `build.yml` (Linux gate) and `build-cross-platform.yml` (macOS+Windows) - workflows are **generated** from `build/Build.CI.GitHubActions.cs` — edit - the attributes + constants there and regenerate (`./build.sh`), never - hand-edit the `.yml`. `build-skip.yml`, `publish-packages-preview.yml`, and - `publish-packages-release.yml` are hand-written. -- **Every publishing lane runs `Test` before it publishes** (#324). - `publish-packages-preview.yml` and `publish-packages-release.yml` both run - a single `dotnet fallout Test Pack` invocation — NUKE executes it as - discrete internal stages (Restore → Compile → Test → Pack) and fails at the - breaking stage, so a test failure stops the job before the push step. Don't - split a lane into separate `dotnet fallout Compile`/`Test`/`Pack` steps — - each invocation re-runs the dependency graph (double-compile); the single - invocation *is* the staged build. -- **Caching** (#328): every workflow caches `~/.nuget/packages` + - `.fallout/temp`, keyed on `global.json` + `**/*.csproj` + - `Directory.Packages.props` (the dependency-affecting set), with a - `restore-keys:` prefix fallback for partial restores. There is no - `packages.lock.json` to add to the key, and build outputs (`bin`/`obj`) are - deliberately **not** cached (stale-artifact correctness risk). -- Don't add `submodules: recursive` to a checkout — there are no submodules - (no `.gitmodules`); it's a dead init step. -- Don't add `develop` (or any working-branch pattern) to the **push** triggers - of the cross-platform workflows — they're release-intent-gated on purpose - (milestone #18 / #318 / #326). diff --git a/.agents/skills/marking-experimental-apis/SKILL.md b/.agents/skills/marking-experimental-apis/SKILL.md deleted file mode 100644 index 099d86d7f..000000000 --- a/.agents/skills/marking-experimental-apis/SKILL.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -name: marking-experimental-apis -description: How to mark a public API as not-yet-stable with [Experimental("FALLOUT0xx")], or deprecate one with [Obsolete(..., DiagnosticId = "FALLOUTOBS0xx")], including diagnostic-ID allocation. Trigger when adding public API that isn't ready for a stability guarantee, or removing/replacing/deprecating an existing public API. ---- - -Fallout has two attributes for public-surface churn, each with its own -diagnostic-ID sequence and registry. Never mix the two sequences. - -## `[Experimental]` — opt-in unstable surface - -Use [`System.Diagnostics.CodeAnalysis.ExperimentalAttribute`](https://learn.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.experimentalattribute) -(ships in the .NET 8+ BCL, no package reference needed) for public API that -isn't ready to commit to a stability guarantee: - -```csharp -using System.Diagnostics.CodeAnalysis; - -[Experimental("FALLOUT001")] -public sealed class NewPluginHost { /* ... */ } -``` - -- **Allocate the next `FALLOUT0xx` ID sequentially, never reused.** Register it - in [docs/experimental-apis.md](../../../docs/experimental-apis.md) in the - same PR. -- **`ExperimentalAttribute` is error-by-default.** A consumer must explicitly - suppress the exact ID (`#pragma warning disable FALLOUT001` or ``) to - use the API — that's the opt-in. -- **Promoting to stable = deleting the attribute.** No cross-branch dance — - the feature already rode the `develop` preview lane. Adding or removing - `[Experimental]` is **not** a breaking change. -- **On a `release/vX.Y` / `main` production line, any risky-but-shipped public - surface must wear it.** That's what keeps the production line trustworthy - while it still carries new work — there's no separate `experimental` branch. -- **Don't apply it speculatively.** Marking an API that's already used - internally breaks the build everywhere it's referenced — suppress every - internal usage in the same change. - -## `[Obsolete]` — deprecating a stable API - -Use [`System.ObsoleteAttribute`](https://learn.microsoft.com/dotnet/api/system.obsoleteattribute) -with a `DiagnosticId` (ships in the .NET 5+ BCL) when a stable public API is on -its way out: - -```csharp -[Obsolete( - "Use [GitHubActionsInputAttribute] instead. Removed in v11.", - DiagnosticId = "FALLOUTOBS001", - UrlFormat = "https://github.com/Fallout-build/Fallout/blob/main/docs/obsolete_apis.md")] -public string[] OnWorkflowDispatchOptionalInputs { get; set; } = new string[0]; -``` - -- **Allocate the next `FALLOUTOBS0xx` ID sequentially, never reused** — a - separate sequence from `FALLOUT0xx` above. Register it in - [docs/obsolete_apis.md](../../../docs/obsolete_apis.md) in the same PR. -- **Always set `DiagnosticId`.** Without one the compiler reports the generic - `CS0618`, so a `TreatWarningsAsErrors` consumer can only fix every usage at - once or blanket-suppress every deprecation. A per-deprecation ID lets them - suppress just this one while they migrate. -- **Adding `[Obsolete]` is not a breaking change** — it's warning-level, so - existing code keeps compiling. The *removal* is the break, and it waits for - the next major. State the removal target in the message (e.g. `Removed in v11.`). -- **Keep the deprecated surface functional.** Prefer bridging the old member to - the new one over leaving it inert, and suppress the internal bridge usage - with `#pragma warning disable` scoped to the exact ID. - -See [AGENTS.md rule 2](../../../AGENTS.md) for how these fit the -backwards-compatibility policy, and the `creating-a-pr` skill for how a -breaking change (as opposed to marking something experimental or obsolete) -needs to be labelled and targeted. diff --git a/.agents/skills/plain-english/SKILL.md b/.agents/skills/plain-english/SKILL.md deleted file mode 100644 index 4542dff93..000000000 --- a/.agents/skills/plain-english/SKILL.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -name: plain-english -description: >- - Write clear, plain English for developer-facing prose aimed at an - international audience. Use this skill whenever you draft or review a pull - request description, commit message, changelog or release-note entry, issue - report, code-review comment, or README / docs prose — especially in - open-source repositories where many contributors read English as a second - language. Trigger it even when the user does not say "plain English": any - time the deliverable is short technical writing that other people will read, - apply these rules. Also use it to rewrite or tighten existing text that is - too long, too hedged, full of idioms, or full of unexplained jargon. ---- - -# Plain English for developer writing - -Goal: text a non-native English reader understands on the first pass, without a -dictionary and without guessing at idioms. Applies to PR descriptions, commit -messages, changelogs, release notes, issue reports, review comments, and docs — -for new text and for rewrites. - -This is the canonical source for AGENTS.md rule 8. Any other file in this repo -that talks about plain-English writing style (for example -[creating-a-pr](../creating-a-pr/SKILL.md)) should link here rather than -repeat these rules — one topic, one home. - -## Rules - -1. **Lead with the ask.** First sentence says what changed and why. Everything - after it is support. - - Before: After a lot of investigation I ended up touching the retry logic - because CI was flaky. - - After: Retry failed uploads up to three times, so transient network errors - stop breaking CI. - -2. **Match length to substance.** A one-line fix gets a one-line description. - No padding, no minimum length to hit. - -3. **Cut filler.** Drop preamble, restating the title, hedging, marketing words - ("elegant", "robust", "seamlessly", "blazing fast"), and emoji headers. - -4. **One idea per sentence.** Do not chain clauses with em-dashes or semicolons. - - Before: This doesn't do X — that stands — it does Y, and gives Z a path - off W. - - After: This does not do X. It does Y. That gives Z a way to move off W. - -5. **No idioms or figurative language.** Say it literally. - - | Figurative | Literal | - | --- | --- | - | blast radius | affects fewer consumers | - | shrinks the gap | closes the gap | - | grace period | temporary fallback | - | ceiling | limit | - | shallow by design | handles the common case only | - | under the hood | internally | - | low-hanging fruit | the easy cases | - -6. **Define jargon on first use, or link it.** Terms like "shim", "sentinel", - or "canonical type" get a one-clause gloss, or a link to the - [glossary](#glossary) below, the first time they appear. Do not assume the - reader knows the vocabulary. - -7. **Gloss every cross-reference.** A bare `#257` tells the reader nothing. - Write "#257 (the ProjectModel rename)". - -8. **Prefer short, common words.** - - | Longer | Shorter | - | --- | --- | - | leverage / utilize | use | - | preserve | keep | - | surfaces | shows | - | remediates | fixes | - | facilitate | help | - | in order to | to | - | a number of | several | - -## Extra rules for issues and PRs - -The GitHub issue forms (`.github/ISSUE_TEMPLATE/*.yml`) define the canonical -shape for humans; the rules below are what AI tools are bound to (a `.yml` -form does not constrain an agent running `gh issue create`). - -- **Link, don't recap.** Reference issues (`#123`), PRs, docs, and code - (`path/to/file.cs:42`) instead of pasting them. -- **Describe outcomes, not your process.** What changed and why it matters — - not the journey you took to get there. -- **Cut what the reader can get elsewhere.** If the diff, a linked issue, or the - discussion thread already carries it, don't repeat it — reference and - summarize. Keep only what the reader *can't* get without you. This is the - single best test when deciding whether a line earns its place. -- **It's probably just an issue.** Don't reach for RFC or ADR framing by - default — most work is a plain story, task, or idea. Reserve RFC/ADR for - genuinely cross-cutting decisions that need a durable record. When in doubt, - write a plain issue. - -### Issue / user story shape - -```markdown -### Problem -<1–2 sentences: what's wrong or missing, and for whom> - -### Outcome - - -### Acceptance criteria -- [ ] -- [ ] -``` - -Optional `### Notes` (≤3 lines) for links or constraints. **Drop any section -that doesn't apply** rather than padding it. - -If there are genuinely open questions, add a short `### Open questions` list -(a handful of one-liners). Do **not** stage a `D1`/`D2`/… decision record in the -issue body — decisions get made in the comment thread or the PR, not -pre-memorialized in the spec before anyone has replied. - -### PR description shape - -```markdown - - -### What changed -- -- - -### Why - - -Closes # -``` - -- **Link the issue it implements** (`Closes #123`, or `Part of #123` for one PR - in a series). Summarize the need in a line — don't recite the issue's - Problem/Outcome/criteria back; the reader can click through. The PR explains - *the change*; the issue holds *the requirement*. -- Add the `⚠️ Breaking change` callout **only** when the change is breaking — see the [creating-a-pr skill](../creating-a-pr/SKILL.md) for what that requires. -- **Don't** restate the title, paste large code/log blocks, recount your - process, or enumerate every touched file — the diff already shows that. -- Keep a `### Verification` line (what you actually ran) and, for a PR in a - series, a short follow-ups list — those are the bits *not* visible in the diff. - -### Anti-patterns - -| Instead of… | Write… | -| --- | --- | -| "This PR introduces a comprehensive refactor that…" | "Replaces reflection dispatch with `IFalloutCommand`." | -| Three paragraphs restating the title | One line, then bullets | -| Pasting the full stack trace inline | Link to the run / collapse in `
      ` | -| "As part of this work, I also…" | A second bullet, or a second PR | -| "This doesn't reclassify #257 — that break stands — it shrinks the blast radius for consumers upgrading from 11.0.1–11.0.12" | "#257 (the ProjectModel rename) is still breaking. This PR only makes upgrading past it easier for 11.0.1–11.0.12 users." | -| "Deliberately shallow… same ceiling as the generated shim" | "This only covers the common case. For everything else, use `fallout-migrate`." | - -## Glossary - -Terms that come up often in issues, PRs, and code comments. Link here (or -gloss the term in one clause) the first time a PR or issue uses one of these — -per rule 6 above, don't assume the reader already knows the vocabulary. - -| Term | Meaning | -| --- | --- | -| **Shim** | A small compatibility layer that makes old code keep compiling/working against a new API, without being the real implementation. | -| **Transition shim** | A shim meant to be temporary — it exists only to ease an upgrade and is expected to be removed later. | -| **Sentinel** (e.g. "consumer sentinel") | A small test project whose only job is to fail the build if something regresses — an early-warning check, not a feature. | -| **Canonical type / namespace** | The current, "real" location of a type — as opposed to an old namespace kept alive only by a shim. | -| **Ceiling** (of a shim/fix) | The limit of what a shim or fix covers — what it does *not* handle, so the reader knows when to reach for something else. | -| **Shallow (by design)** | The change intentionally covers only the common case, not every possible scenario. | -| **Blast radius** | How many consumers/how much code is affected by a change. | - -## Rewriting someone else's text - -Keep the technical meaning and any real caveats — a genuine "Linux only" is not -filler. Change wording and structure, not substance. Flag an ambiguous sentence -instead of guessing at what it meant. diff --git a/.claude/agents/story-writer.md b/.claude/agents/story-writer.md deleted file mode 100644 index 495599ac6..000000000 --- a/.claude/agents/story-writer.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: story-writer -description: Drafts GitHub issues and user stories for this repo — terse, outcome-focused, and to the canonical shape. Use when asked to create, write, or file an issue/story. -tools: Read, Grep, Glob, Bash -model: sonnet ---- - -You write GitHub issues and user stories for the Fallout repo. Your output is -the issue body itself, not a conversation about it. - -**Before writing**, read `.agents/skills/plain-english/SKILL.md` -— it is the binding style contract. Follow it exactly. - -Defaults: - -- Use the **Problem → Outcome → Acceptance criteria** shape. Drop any section - that doesn't apply rather than padding it. -- Be terse. Lead with the point. No preamble, no restating the title, no - hedging, no marketing tone, no emoji headers. Match length to substance. -- Prefer linking (`#123`, `path/to/file.cs:42`) over pasting. -- Outcomes describe observable behaviour, not implementation. - -When the request is underspecified, ask at most 1–2 sharp questions, then write. -Do not invent acceptance criteria the user didn't imply — leave a `- [ ]` stub -if unknown. - -If asked to file it, run `gh issue create` with `--title` and a `--body` that -matches the shape. Apply `--label enhancement` for stories unless told -otherwise, and the appropriate `target/vCurrent`/`target/vNext` label per the -`creating-a-pr` skill (`.agents/skills/creating-a-pr/SKILL.md`). -Report the created issue URL and nothing else. diff --git a/.claude/commands/new-issue.md b/.claude/commands/new-issue.md deleted file mode 100644 index 362db8f09..000000000 --- a/.claude/commands/new-issue.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -description: Draft (and optionally file) a terse, outcome-focused GitHub issue to the repo's canonical shape. -argument-hint: -allowed-tools: Read, Bash(gh issue create:*), Bash(gh label list:*) ---- - -Read `.agents/skills/plain-english/SKILL.md` and follow it as the binding -style contract. Then draft a GitHub issue for: **$ARGUMENTS** - -Assemble the body to the canonical shape: - -```markdown -### Problem -<1–2 sentences> - -### Outcome - - -### Acceptance criteria -- [ ] -- [ ] -``` - -Rules: - -- Terse. Lead with the point. No preamble, no restating the title, no filler. -- Drop `Acceptance criteria` (and add a short `### Notes`) only if it doesn't - fit the ask. Don't invent criteria — leave `- [ ]` stubs if unknown. -- Prefer links (`#123`, `path/to/file.cs:42`) over pasted blocks. - -Show me the drafted title and body first. **Do not file it until I confirm.** -On confirmation, run `gh issue create --title "…" --body "…" --label enhancement` -plus the correct `target/vCurrent`/`target/vNext` label (see the `creating-a-pr` -skill), and report only the resulting issue URL. diff --git a/.claude/skills/restructure-pr-commits/SKILL.md b/.claude/skills/restructure-pr-commits/SKILL.md deleted file mode 100644 index 02d5721fe..000000000 --- a/.claude/skills/restructure-pr-commits/SKILL.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -name: restructure-pr-commits -description: "Restructure the commits on an existing PR into focused, reviewable commits" ---- - -Restructure the commits on PR `` into focused, reviewable commits. -Follow these steps in order exactly. - -## 1 — Find what the PR actually changes - -Run: -``` -git diff upstream/main HEAD --stat -``` - -This is the authoritative list of files the PR modifies. `git log` is misleading -on branches kept up to date via merge: merge commits drag upstream history into the -log as if it were authored on this branch — it isn't. - -## 2 — Find the branch's own commits - -Run: -``` -git log --first-parent --no-merges upstream/main..HEAD --oneline -``` - -This shows only commits made directly on this branch. - -## 3 — Create a backup branch - -``` -git branch backup-pr- HEAD -``` - -Do this before changing anything. Never skip this step. - -## 4 — Build the restructured history - -Check out a fresh branch from `upstream/main`: -``` -git checkout upstream/main -b restructured-pr- -``` - -Then restore the changed files from the backup: -``` -git checkout backup-pr- -- -``` - -Handle renames explicitly: `git rm ` then `git checkout backup-pr- -- `. - -Commit in logical groups — one concern per commit. Commit message rules (from the project's AGENTS.md): -- Functional imperative phrases; no conventional-commit prefixes (`fix:`, `feat:`, etc.) -- Subject completes "This commit will…" without saying so -- Body (when needed) explains *why*, not *what*; no file/class/type names - -## 5 — Verify file content is unchanged - -Run both and report the output: -``` -git diff HEAD backup-pr- -git diff HEAD upstream/main --stat -``` - -The first command must produce **no output**; if it does, stop and investigate before continuing. -The second must list **exactly the same files** as step 1. - -## 6 — Stop and wait for explicit confirmation - -Show the new `git log --oneline` and ask the user to confirm the history looks -correct. Do not proceed until the user explicitly says yes. - -## 7 — Push with --force-with-lease only after confirmation - -``` -git push origin HEAD: --force-with-lease -``` - -Never use `--force` alone. - -## 8 — Update the PR title and description after confirmation - -Rewrite the PR title and description to match the restructured commits. -Structure: Summary → one Changes section per commit → optional Combined effect. -Each Changes section maps 1-to-1 to a commit. Apply the PR-creation flow from -`.agents/skills/creating-a-pr/SKILL.md` for labels and breaking-change callouts. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 796f7d718..9df838077 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,5 @@ - + diff --git a/.github/release.yml b/.github/release.yml index 0cec8879e..c08448eb0 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -2,8 +2,9 @@ # # GitHub reads this to auto-generate release notes, grouping merged PRs into the # sections below by label. It is ALSO the canonical list of changelog labels that -# tooling and AI apply at PR-creation time — see the `creating-a-pr` skill -# (.agents/skills/creating-a-pr/SKILL.md) for the full PR-creation flow. +# tooling and AI apply at PR-creation time — see the `creating-a-pr` skill in the +# `fallout-core` plugin of Fallout.Workbench for the full PR-creation flow: +# https://github.com/Fallout-build/Fallout.Workbench/blob/main/plugins/fallout-core/skills/creating-a-pr/SKILL.md # # When raising a PR: apply the one category label that matches the change (the # blurbs below say which is which), in the same `gh pr create` call, alongside the diff --git a/AGENTS.md b/AGENTS.md index 2383be1b5..4aa91524f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,44 +1,24 @@ # AGENTS.md -Guidance for AI coding tools (Claude Code, GitHub Copilot, Cursor, Aider, Codex, etc.) working in this repo. +Brief for AI coding tools working in this repo. Human contributors: see [CONTRIBUTING.md](CONTRIBUTING.md). -This is the **canonical brief** — always-on rules plus a routing table to everything else. GitHub Copilot reads this file natively. Claude Code reads `CLAUDE.md`, which imports this file and additionally lists each skill under `.agents/skills/` by path, since Claude Code doesn't auto-discover that folder the way Copilot CLI does. +## Before you change anything -## Documentation map - -One topic, one home — anything that duplicates another layer gets deleted, not synced: - -- **`docs/adr/`** — the decision and why it was made. Immutable history; a superseded ADR says so and points at its replacement. -- **`docs/` (everything else)** — reference material and maintainer runbooks: the current "how it works" / "how to operate it". -- **`.agents/skills/`** — on-demand procedures: what an agent does for a specific task, loaded only when the task matches. -- **This file** — the rules that apply to every session, plus the routing table below. +- Read [CONTRIBUTING.md](CONTRIBUTING.md). It holds the rules for every contribution: backwards compatibility, package versions, tests, commit and PR style, labels, and plain English. +- Skills for this repo live in [Fallout.Workbench](https://github.com/Fallout-build/Fallout.Workbench), not here. In Claude Code: + ``` + /plugin marketplace add Fallout-build/Fallout.Workbench + /plugin install fallout-workbench@fallout-workbench + /plugin install fallout-core@fallout-workbench + ``` + Other tools can read the `skills/` and `plugins/fallout-core/skills/` folders in that repo directly. +- Opening a PR? Use the `creating-a-pr` skill from `fallout-core`. Review blocks a PR that skips it. ## What this project is -**Fallout** is a build automation system for C#/.NET — a hard-fork successor to [NUKE](https://github.com/nuke-build/nuke), originally by [Matthias Koch](https://github.com/matkoch), now under new maintenance. The build is itself a C# console app (`build/_build.csproj`), so any framework change can be dogfooded by running `./build.ps1` (Windows) or `./build.sh` (Linux/macOS). The rebrand from `Nuke.*` to `Fallout.*` has structurally landed; `Nuke.*` survives only as consumer transition shims under `src/Shims/` — see [docs/Migration/from-nuke.md](docs/Migration/from-nuke.md). - -## Versioning & channels - -Classic GitFlow, staying on semver `10.x` — see [ADR-0009](docs/adr/0009-gitflow-and-semver-reversion.md) (replaces the calendar-versioning [ADR-0004](docs/adr/0004-calendar-versioning-and-dual-pace-channels.md)). **GitHub Packages = test/preview/rc; nuget.org = production.** - -| Branch | Role | Publishes | -| --- | --- | --- | -| `develop` | Integration trunk, default branch, sole preview lane. All work lands here, including breaking work gated behind `[Experimental]`. | `-preview` → GitHub Packages only | -| `release/vX.Y` | Stabilizes the next release; cut from `develop` on demand, not ahead of time. Non-breaking fixes only after the cut. | `-rc.N` → GitHub Packages | -| `main` | Production trunk; takes only `release/vX.Y` (GA) or `hotfix/vX.Y.Z` merges. | GA tags → nuget.org (opt-in) + GitHub Packages + Releases | -| `support/v10` (+ `hotfix/v10.x`) | Legacy line for versions before `10.4`. Security/critical fixes only. | Tags, same channels as `main` | +Fallout is a build automation system for C#/.NET. It is a hard-fork successor to [NUKE](https://github.com/nuke-build/nuke). The build is itself a C# console app (`build/_build.csproj`), so you can test any framework change by running `./build.ps1` (Windows) or `./build.sh` (Linux/macOS). -`MAJOR` stays `10` until a breaking change is actually needed — there's no fixed date for v11, and it's deferred as long as possible. Not-yet-stable public APIs ship behind `[Experimental("FALLOUT0xx")]` on any channel — see the `marking-experimental-apis` skill. Full model: [docs/branching-and-release.md](docs/branching-and-release.md). - -**Active work** — rebrand completion + plugin-architecture internal foundation ([milestone #6](https://github.com/Fallout-build/Fallout/milestone/6)), shipping as non-breaking `10.x` releases. **No public plugin SDK yet** — see [docs/roadmap.md](docs/roadmap.md). - -## Stack - -- .NET SDK pinned in `global.json` (currently `10.0.100`, `rollForward: latestMinor`). -- Central package versions in `Directory.Packages.props` — never add a `Version=` to an individual `PackageReference`. -- xUnit + FluentAssertions + Verify.Xunit for tests. -- Solution file is `fallout.slnx` (new XML solution format, not `.sln`). -- Dependency updates: Dependabot opens monthly grouped PRs, but only for the test, build-time and tool-only packages in the `allow` list of `.github/dependabot.yml`. Packages that ship to consumers are updated deliberately — see "Updating dependencies" in [docs/dependencies.md](docs/dependencies.md). Adding a library? Put it in the right group of `Directory.Packages.props`. +For the layout, branching and release model, see [docs/architecture.md](docs/architecture.md) and [docs/branching-and-release.md](docs/branching-and-release.md). ## Common commands @@ -54,60 +34,5 @@ dotnet build fallout.slnx dotnet test tests/Fallout.Common.Tests/Fallout.Common.Tests.csproj ``` -Do commit code generated by `GenerateTools` — the `.Generated.cs` files are checked in, and `VerifyGeneratedTools` fails CI if a `.json` spec edit isn't accompanied by regenerating and committing its wrapper. - -## Critical rules (read this every session) - -1. **At PR-creation time, use the `creating-a-pr` skill** (`.agents/skills/creating-a-pr/SKILL.md`). It covers branching off a fork, creating the PR as a draft, and applying the `target/vCurrent`/`target/vNext` and changelog-category labels. Breaking changes get extra steps there — they target `develop` behind `[Experimental("FALLOUT0xx")]`, never a `release/vX.Y` or `main` production branch. Not optional — review will block a PR that skips this. -2. **Default to backwards compatibility.** Prefer an additive change over a breaking one. Before changing a public signature, removing an API, renaming a package, or changing an on-disk format, ask: can this be additive instead? Prefer `[Obsolete]`, transition shims (`src/Shims/` + `Fallout.SourceGenerators.TransitionShimGenerator`), `[Experimental("FALLOUT0xx")]`, feature flags, and extra overloads over a hard break — see the `marking-experimental-apis` skill for how to apply either attribute. When a break really can't be avoided, it follows rule 1's flow. See [#262](https://github.com/Fallout-build/Fallout/issues/262) for the broader discussion. -3. **Central package versions only** — add to `Directory.Packages.props`, never `Version=` inline. -4. **Tests next to code** — every `src/Foo` has a `tests/Foo.Tests` sibling. Mirror namespaces. -5. **Stay on xUnit + FluentAssertions + Verify.** Don't introduce new test frameworks. Test names are short, present-tense descriptions of observable behavior (not method calls); test classes/files/projects use the `Specs` suffix; mark Arrange/Act/Assert with Pascal-case comments — see [CONTRIBUTING.md](CONTRIBUTING.md#pull-requests) for the full convention with examples. -6. **No per-file license headers.** The MIT notice lives in [`LICENSE`](LICENSE) at the repo root — single source of truth. Don't reintroduce header preambles on new files. (Vendored third-party code under `src/Persistence/Fallout.Persistence.Solution/` keeps its own upstream Microsoft headers — leave those alone.) -7. **No conventional commits.** Do not use `feat:`, `fix:`, `chore:`, `refactor:`, or any other conventional-commit prefix on commit messages or PR titles. Write functional descriptions that explain what the commit or PR accomplishes — e.g. "Add retry logic to the HTTP tool wrapper". The only exception is the `!` suffix (e.g. `fix(security)!: …`), used purely as a breaking-change detection signal. -8. **Write terse, plain English — in chat responses, commit messages, PR/issue descriptions, and code comments alike.** Lead with the point; bullets over prose; cut filler (no preamble, no hedging, no marketing tone). Many contributors read English as a second language, so: - - **One idea per sentence.** Split stacked clauses instead of joining them with em-dashes or semicolons. - - **No idioms or figurative language** ("blast radius", "ceiling", "shallow by design"). Say what you mean literally: "affects fewer consumers", "limit", "handles the common case only". - - **Define or link repo jargon on first use** — see the `plain-english` skill's glossary — don't assume the reader already knows the vocabulary. - - **Gloss a cross-reference in 3–5 words** instead of a bare `#257`. - - **Prefer short, common words** — "use" not "leverage", "keep" not "preserve". - - Full rules and examples: the `plain-english` skill, including issue/PR shape (Problem → Outcome → Acceptance criteria, anti-patterns). -9. **Never ping the former NUKE maintainer, Matthias Koch (GitHub handle `matkoch`).** He no longer maintains Fallout and does not want the notifications. Do not `@`-mention him (never write `@` before his handle, in any file or GitHub surface), add him as a reviewer/assignee, request his review, tag him in issue/PR/commit text, or add him as a commit co-author/`Co-authored-by:` trailer — from any AI tool. Credit NUKE's origin by name or a plain profile link — just never with a leading `@` (a bare `@handle` is what fires a mention). - -## Repository map - -| Path | What lives here | -| --- | --- | -| `src/` | All production library projects (`src/Fallout./Fallout..csproj`). The exception is `src/Shims/` — three transition shims for NUKE-era consumers. | -| `tests/` | All test projects (`tests/Fallout..Tests/Fallout..Tests.csproj`), plus the shim test projects. | -| `vendor/` | Vendored third-party source we maintain a fork of (`vs-solutionpersistence`, packaged as `Fallout.VisualStudio.SolutionPersistence`). | -| `build/` | The build orchestrator (`_build.csproj` + `Build.*.cs` partial files) — the canonical example of how to consume the framework. | -| `docs/` | Documentation site content, architecture notes, and ADRs. | -| `.agents/skills/` | On-demand agent procedures (see the routing table below). | -| `.assets/` | Images, icons, logos — anything binary and non-code. Don't reintroduce a top-level `images/` folder. | -| Root | Solution file (`fallout.slnx`), shared MSBuild plumbing (`Directory.Build.props/targets`, `Directory.Packages.props`), `AssemblyInfo.cs`, project conventions (`README.md`/`CONTRIBUTING.md`/`LICENSE`/`AGENTS.md`/`CLAUDE.md`). | - -Production code lives under `src/`, tests under `tests/` — don't reintroduce a combined `source/` tree (the previous monorepo layout); see [docs/architecture.md](docs/architecture.md) for why. `src/Fallout.Common/Tools//.json` files are the source of truth for tool wrappers; the `.cs` next to each is generated. Source generators (`src/Fallout.SourceGenerators`) produce per-target code at compile time — if a symbol seems missing, check whether it's generated. - -## Routing table - -| Doing this? | Use | -| --- | --- | -| Opening a PR, writing commits, picking a base branch | `creating-a-pr` skill | -| Writing any PR, commit, issue, or doc text | `plain-english` skill | -| Adding/extending a `Tools//.json` wrapper | `adding-a-tool-wrapper` skill | -| Adding public API that isn't stable yet, or deprecating one | `marking-experimental-apis` skill | -| Proposing a new public API before writing code | [CONTRIBUTING.md § Proposing new public API](CONTRIBUTING.md#proposing-new-public-api) | -| Touching `.github/workflows/**` or `build/Build.CI.GitHubActions.cs` | `editing-ci-workflows` skill | -| Tagging, publishing, hotfixing, or cutting a release branch | `cutting-a-release` skill | -| Adding a rename/rewrite rule to `fallout-migrate` | `adding-a-migration-step` skill | -| Understanding the branching/versioning model in depth | [docs/branching-and-release.md](docs/branching-and-release.md), [ADR-0009](docs/adr/0009-gitflow-and-semver-reversion.md) | -| Understanding the repo layout / engine internals | [docs/architecture.md](docs/architecture.md), [docs/engine-de-statification.md](docs/engine-de-statification.md) | -| Consumer-facing NUKE → Fallout migration | [docs/Migration/from-nuke.md](docs/Migration/from-nuke.md) | -| Roadmap, milestones, open RFCs | [docs/roadmap.md](docs/roadmap.md) | -| Adding/auditing a third-party dependency | [docs/dependencies.md](docs/dependencies.md) | -| Repo jargon (shim, sentinel, canonical type, …) | `plain-english` skill (glossary section) | -| Contributor-facing flow (issues, PR review, merging) | [CONTRIBUTING.md](CONTRIBUTING.md) | - -Skills live in `.agents/skills//SKILL.md`, each with its own `references/` for anything longer than a screenful. +- The .NET SDK is pinned in `global.json`. The solution file is `fallout.slnx` (XML format, not `.sln`). +- Commit code generated by `GenerateTools`. The `.Generated.cs` files are checked in, and `VerifyGeneratedTools` fails CI if a `.json` spec changes without its regenerated wrapper. diff --git a/CLAUDE.md b/CLAUDE.md index 2e1b2f71e..a17baa0d8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,17 +1,3 @@ # CLAUDE.md -This project uses [`AGENTS.md`](AGENTS.md) as its canonical brief for AI coding tools. Claude Code imports it via the file-reference syntax below. - @./AGENTS.md - -## Skills - -Skills live under `.agents/skills/` (tool-neutral — Copilot CLI auto-discovers this folder; Claude Code does not, hence this explicit list). Read the linked `SKILL.md` when the task matches: - -- [.agents/skills/creating-a-pr/SKILL.md](.agents/skills/creating-a-pr/SKILL.md) — opening a PR, writing commits, picking a base branch, writing plain terse PR/issue descriptions. -- [.agents/skills/plain-english/SKILL.md](.agents/skills/plain-english/SKILL.md) — writing any PR, commit, issue, or doc text so non-native English readers follow it on the first pass. -- [.agents/skills/adding-a-tool-wrapper/SKILL.md](.agents/skills/adding-a-tool-wrapper/SKILL.md) — adding or extending a `Tools//.json` wrapper. -- [.agents/skills/marking-experimental-apis/SKILL.md](.agents/skills/marking-experimental-apis/SKILL.md) — adding public API that isn't stable yet, or deprecating one. -- [.agents/skills/editing-ci-workflows/SKILL.md](.agents/skills/editing-ci-workflows/SKILL.md) — touching `.github/workflows/**` or `build/Build.CI.GitHubActions.cs`. -- [.agents/skills/cutting-a-release/SKILL.md](.agents/skills/cutting-a-release/SKILL.md) — tagging, publishing, promoting, or cutting a release branch. -- [.agents/skills/adding-a-migration-step/SKILL.md](.agents/skills/adding-a-migration-step/SKILL.md) — adding a rename/rewrite rule to `fallout-migrate`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40d91981a..9daa46f66 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,10 +54,17 @@ This applies to a new public type or member, not a small additive overload or a - Branch from `develop` (the base for all PRs). Name your branch `feature/`, `bugfix/`, or `chore/`. - **Open it as a draft** (`gh pr create --draft`, or the draft option in the GitHub UI). Mark it ready for review only once it's done — this keeps incomplete work out of the review queue. - Make sure your employer allows the contribution. -- Read [AGENTS.md](AGENTS.md) for the codebase conventions — package versions go in `Directory.Packages.props`, tests live next to code, no per-file license headers (the `LICENSE` file at the root is the single source of truth). (AGENTS.md is the canonical brief for both human contributors and AI tools; GitHub Copilot reads it natively and `CLAUDE.md` points to it.) +- Read the rules below. Package versions go in `Directory.Packages.props`, and tests live next to code. - The bootstrappers are now thin: `./build.ps1` / `./build.sh` provision .NET if needed, then run `dotnet tool restore` + `dotnet fallout "$@"`. The `Fallout.GlobalTool` version is pinned in `.config/dotnet-tools.json`. - Run `./build.ps1 Test` (or `./build.sh Test`, or directly `dotnet fallout Test` once your tools are restored) locally first. +### Rules for every contribution + +- **Default to backwards compatibility.** Prefer an additive change over a breaking one. Before you change a public signature, remove an API, rename a package, or change an on-disk format, ask: can this be additive instead? Prefer `[Obsolete]`, transition shims (`src/Shims/` + `Fallout.SourceGenerators.TransitionShimGenerator`), `[Experimental("FALLOUT0xx")]`, feature flags, and extra overloads over a hard break. When a break cannot be avoided, label it `breaking-change` and follow the steps under "When writing the PR". See [#262](https://github.com/Fallout-build/Fallout/issues/262) for the wider discussion. +- **No per-file license headers.** The MIT notice lives in [`LICENSE`](LICENSE) at the repo root. Do not add header preambles to new files. Vendored third-party code under `src/Persistence/Fallout.Persistence.Solution/` keeps its own upstream Microsoft headers. Leave those alone. +- **Write terse, plain English** in commit messages, PR and issue descriptions, and code comments. Many contributors read English as a second language. Lead with the point, use one idea per sentence, avoid idioms, and prefer short common words. The `plain-english` skill in [Fallout.Workbench](https://github.com/Fallout-build/Fallout.Workbench/blob/main/skills/plain-english/SKILL.md) has the full rules and examples. +- **Do not mention the former NUKE maintainer, Matthias Koch (GitHub handle `matkoch`).** He no longer maintains Fallout and does not want the notifications. Never write `@` before his handle. Do not add him as a reviewer or assignee, request his review, tag him in issue, PR or commit text, or add him as a `Co-authored-by:` trailer. Credit NUKE's origin by name or a plain profile link, without a leading `@`. + ### When writing the PR - **Write functional commit and PR titles** — describe what the change accomplishes, not how it's categorised. Do not use conventional-commit prefixes (`feat:`, `fix:`, `chore:`, `refactor:`, etc.). Good examples: "Add retry logic to the HTTP tool wrapper", "Fix null-reference in target dependency resolution". The `!` suffix (e.g. `fix(security)!: …`) is recognised only as a breaking-change detection signal, not a general style requirement. @@ -69,11 +76,11 @@ This applies to a new public type or member, not a small additive overload or a - **AAA structure with Pascal-case comments** — `// Arrange`, `// Act`, `// Assert`. Omit a section's comment when there's nothing to arrange (e.g. constructor fixtures already cover it). - **Disk-based fixtures use a constructor + `IDisposable.Dispose()`**, not per-test `try/finally` — xUnit creates a fresh instance per `[Fact]`, so the constructor is Arrange and `Dispose()` is teardown. Use `AbsolutePath.Temp(prefix)` for the scratch directory. See `MigrationIntegrationSpecs.cs` and `BumpDotNetVersionStepSpecs.cs` for the pattern. - Commit the regenerated `.cs` output alongside the `.json` spec — `VerifyGeneratedTools` fails CI if they drift. -- **Label the PR `target/vCurrent`** for the current release line (use `target/vNext` for work held for the next major). **Breaking changes wait for the next major.** They land on `develop`, behind `[Experimental("FALLOUT0xx")]` (or, if that doesn't fit, on a short-lived branch off `develop`) — never on a `release/vX.Y` or `main` production branch. They also get a `breaking-change` label plus a `⚠️ Breaking change` callout in the PR description that names the migration path. Surface that isn't ready to commit to yet can ship behind `[Experimental("FALLOUT0xx")]` instead of being held back. See the `creating-a-pr` skill (`.agents/skills/creating-a-pr/SKILL.md`) for the full procedure. +- **Label the PR `target/vCurrent`** for the current release line (use `target/vNext` for work held for the next major). **Breaking changes wait for the next major.** They land on `develop`, behind `[Experimental("FALLOUT0xx")]` (or, if that doesn't fit, on a short-lived branch off `develop`) — never on a `release/vX.Y` or `main` production branch. They also get a `breaking-change` label plus a `⚠️ Breaking change` callout in the PR description that names the migration path. Surface that isn't ready to commit to yet can ship behind `[Experimental("FALLOUT0xx")]` instead of being held back. AI tools: use the [`creating-a-pr` skill](https://github.com/Fallout-build/Fallout.Workbench/blob/main/plugins/fallout-core/skills/creating-a-pr/SKILL.md) for the full procedure. ### Tool wrappers -Tool wrapper JSON lives under `src/Fallout.Common/Tools//.json`. See the `adding-a-tool-wrapper` skill (`.agents/skills/adding-a-tool-wrapper/SKILL.md`) for the recipe: copy a neighbour's shape, cover a full command with all its arguments, regenerate with `./build.ps1 GenerateTools`, and commit the regenerated `.cs` alongside the `.json` spec. +Tool wrapper JSON lives under `src/Fallout.Common/Tools//.json`. Copy a neighbour's shape, cover a full command with all its arguments, regenerate with `./build.ps1 GenerateTools`, and commit the regenerated `.cs` alongside the `.json` spec. AI tools: use the `adding-a-tool-wrapper` skill from the `fallout-core` plugin (see [AGENTS.md](AGENTS.md)). ### After opening a PR diff --git a/docs/architecture.md b/docs/architecture.md index 3eb91fd46..43600a5f0 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -6,8 +6,8 @@ Canonical reference for how the Fallout repo is laid out, what each project does ``` . -├── .agents/, .claude/ Skills and settings for AI coding tools ├── .assets/ Logos and social-preview images (PNG + SVG) +├── .claude/ Shared Claude Code settings (skills live in Fallout.Workbench) ├── .config/ dotnet-tools.json (pins the `fallout` global tool used by CI) ├── .fallout/ Build orchestrator runtime state (committed: schema, parameters) ├── .github/ GitHub Actions workflows, Dependabot config, issue/PR templates diff --git a/docs/branching-and-release.md b/docs/branching-and-release.md index baf1ad874..8b82102bc 100644 --- a/docs/branching-and-release.md +++ b/docs/branching-and-release.md @@ -2,7 +2,7 @@ Maintainer reference for branching, releasing, hotfixing, and the GitHub Environments that gate publishes. The model is [ADR-0009](adr/0009-gitflow-and-semver-reversion.md) (classic GitFlow, staying on semver `10.x`), which replaces [ADR-0004](adr/0004-calendar-versioning-and-dual-pace-channels.md) and changes part of [ADR-0001](adr/0001-release-branch-model.md) ([milestone #13](https://github.com/Fallout-build/Fallout/milestone/13), [RFC #267](https://github.com/Fallout-build/Fallout/issues/267)). It keeps [ADR-0007](adr/0007-cut-release-branch-on-demand.md)'s on-demand cut and [ADR-0008](adr/0008-collapse-experimental-into-main.md)'s decision against a separate `experimental` branch. -> **Audience.** Maintainers cutting releases or hotfixing older lines. Contributors filing PRs against `develop` don't need this — see [CONTRIBUTING.md](https://github.com/Fallout-build/Fallout/blob/main/CONTRIBUTING.md). An AI tool asked to cut a release should use the `cutting-a-release` skill (`.agents/skills/cutting-a-release/SKILL.md`), which follows this doc. +> **Audience.** Maintainers cutting releases or hotfixing older lines. Contributors filing PRs against `develop` don't need this — see [CONTRIBUTING.md](https://github.com/Fallout-build/Fallout/blob/main/CONTRIBUTING.md). An AI tool asked to cut a release should use the [`cutting-a-release` skill](https://github.com/Fallout-build/Fallout.Workbench/blob/main/plugins/fallout-core/skills/cutting-a-release/SKILL.md) from Fallout.Workbench, which follows this doc. ## Branches @@ -152,4 +152,4 @@ nuget.org's `Fallout.*` prefix reservation is per-ID, not per-prefix-wildcard: C - [milestone #13](https://github.com/Fallout-build/Fallout/milestone/13) — the original work-breakdown. - [RFC #267](https://github.com/Fallout-build/Fallout/issues/267) — original design discussion. - [CONTRIBUTING.md](https://github.com/Fallout-build/Fallout/blob/main/CONTRIBUTING.md) — contributor-facing flow. -- `.agents/skills/cutting-a-release/SKILL.md` — the on-demand agent procedure that follows this doc. +- [`cutting-a-release` skill](https://github.com/Fallout-build/Fallout.Workbench/blob/main/plugins/fallout-core/skills/cutting-a-release/SKILL.md) (in Fallout.Workbench) — the agent procedure that follows this doc. diff --git a/docs/experimental-apis.md b/docs/experimental-apis.md index 3d6a57390..f0d0b3942 100644 --- a/docs/experimental-apis.md +++ b/docs/experimental-apis.md @@ -2,7 +2,7 @@ Fallout marks not-yet-stable public APIs with [`System.Diagnostics.CodeAnalysis.ExperimentalAttribute`](https://learn.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.experimentalattribute) so consumers opt into instability deliberately. This page is the **canonical registry of allocated `FALLOUT0xx` diagnostic IDs**. -See [ADR-0004 §5](adr/0004-calendar-versioning-and-dual-pace-channels.md#5-experimental-for-opt-in-unstable-apis) (carried forward unchanged by [ADR-0009](adr/0009-gitflow-and-semver-reversion.md)) for the decision and the `marking-experimental-apis` skill (`.agents/skills/marking-experimental-apis/SKILL.md`) for the contributor rules. +See [ADR-0004 §5](adr/0004-calendar-versioning-and-dual-pace-channels.md#5-experimental-for-opt-in-unstable-apis) (carried forward unchanged by [ADR-0009](adr/0009-gitflow-and-semver-reversion.md)) for the decision and the [`marking-experimental-apis` skill](https://github.com/Fallout-build/Fallout.Workbench/blob/main/plugins/fallout-core/skills/marking-experimental-apis/SKILL.md) from Fallout.Workbench for the contributor rules. ## How it works diff --git a/docs/obsolete_apis.md b/docs/obsolete_apis.md index 3056065db..389aa136a 100644 --- a/docs/obsolete_apis.md +++ b/docs/obsolete_apis.md @@ -4,7 +4,7 @@ Fallout deprecates public APIs with [`System.ObsoleteAttribute`](https://learn.m This is the counterpart to the [`[Experimental]` registry](experimental-apis.md): `[Experimental]` gates *not-yet-stable* surface you opt into (error-by-default); `[Obsolete]` marks *on-the-way-out* surface that still works (warning-by-default). The two use **separate ID sequences** — `FALLOUTOBS0xx` here, `FALLOUT0xx` there — so a suppression can never cross the two. -See the `marking-experimental-apis` skill (`.agents/skills/marking-experimental-apis/SKILL.md`) for the contributor rules. +See the [`marking-experimental-apis` skill](https://github.com/Fallout-build/Fallout.Workbench/blob/main/plugins/fallout-core/skills/marking-experimental-apis/SKILL.md) (in Fallout.Workbench) for the contributor rules. ## How it works