diff --git a/.fallout/build.schema.json b/.fallout/build.schema.json
index 75375d2..86ca2ac 100644
--- a/.fallout/build.schema.json
+++ b/.fallout/build.schema.json
@@ -29,8 +29,8 @@
"GitHubRelease",
"Images",
"Push",
+ "PushDevelop",
"PushDockerHub",
- "PushEdge",
"PushGhcr",
"ReleaseBundle",
"Test",
diff --git a/.github/workflows/publish-edge.yml b/.github/workflows/publish-develop.yml
similarity index 91%
rename from .github/workflows/publish-edge.yml
rename to .github/workflows/publish-develop.yml
index 5e0a3dc..c445b96 100644
--- a/.github/workflows/publish-edge.yml
+++ b/.github/workflows/publish-develop.yml
@@ -9,12 +9,12 @@
#
# - To trigger manual generation invoke:
#
-# fallout --generate-configuration GitHubActions_publish-edge --host GitHubActions
+# fallout --generate-configuration GitHubActions_publish-develop --host GitHubActions
#
#
# ------------------------------------------------------------------------------
-name: publish-edge
+name: publish-develop
on:
push:
@@ -49,8 +49,8 @@ jobs:
global-json-file: global.json
- name: 'Restore: dotnet tools'
run: dotnet tool restore
- - name: 'Run: PushEdge'
- run: dotnet fallout PushEdge
+ - name: 'Run: PushDevelop'
+ run: dotnet fallout PushDevelop
env:
RegistryUser: ${{ secrets.REGISTRY_USER }}
RegistryPassword: ${{ secrets.REGISTRY_PASSWORD }}
diff --git a/CLAUDE.md b/CLAUDE.md
index 67f82a0..02c8c6c 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -190,7 +190,7 @@ dotnet fallout Test # same thing via the tool, which is what CI invokes
> Change the attribute, then regenerate — once per workflow:
> ```bash
> dotnet fallout --generate-configuration GitHubActions_build --host GitHubActions
-> # …and publish-edge · publish-ghcr · publish-release · publish-dockerhub
+> # …and publish-develop · publish-ghcr · publish-release · publish-dockerhub
> ```
### Branching — GitFlow (2026-08-16)
@@ -200,7 +200,7 @@ tagged `v*`. Work goes `feat|fix|chore|docs/*` → PR into `develop`. A release
`release/*` window) **fast-forwarded** into `main`, then tagged. `hotfix/*` is cut from `main` and **must**
be ported back to `develop`.
-- Every non-docs push to `develop` republishes the images as `:edge` (`PushEdge`).
+- Every non-docs push to `develop` republishes the images as `:develop` (`PushDevelop`).
- `GitHubRelease` **refuses** a tag that is not reachable from `main` or `support/*` — the trunk is
never tagged for release.
- **Never merge a release PR with GitHub's button.** It rewrites the commits, which severs the
diff --git a/README.md b/README.md
index 858bf78..91e5b64 100644
--- a/README.md
+++ b/README.md
@@ -452,7 +452,7 @@ pinned as a local dotnet tool, so run `dotnet tool restore` once on a fresh clon
**The whole CI/CD pipeline is Fallout.** Every workflow under `.github/workflows/` is *generated*
from the `[GitHubActions]` attributes in [`build/Build.CI.GitHubActions.cs`](build/Build.CI.GitHubActions.cs),
and each one only provisions a runner and invokes a target — the gate runs `Test`, the trunk runs
-`PushEdge`, a tag runs `PushGhcr` and `GitHubRelease`. Edit the attribute, not the YAML, or your
+`PushDevelop`, a tag runs `PushGhcr` and `GitHubRelease`. Edit the attribute, not the YAML, or your
change is overwritten:
```bash
@@ -504,8 +504,8 @@ gh pr create --base develop --label enhancement # one category label — th
### Running the trunk
-Every push to `develop` republishes the images as `:edge` (multi-arch, GHCR). Point an existing
-deployment's `.env` at that tag to follow along — it moves under you, migrations included, and
+Every push to `develop` republishes the images as `:develop` (multi-arch, GHCR and Docker Hub).
+Point an existing deployment's `.env` at that tag to follow along — it moves under you, migrations included, and
downgrading back to a release is not supported, so back up first.
---
diff --git a/build/Build.CI.GitHubActions.cs b/build/Build.CI.GitHubActions.cs
index 06511e4..69bae1a 100644
--- a/build/Build.CI.GitHubActions.cs
+++ b/build/Build.CI.GitHubActions.cs
@@ -43,9 +43,10 @@
},
InvokedTargets = new[] { nameof(Test) })]
-// ── The edge channel (GitFlow's preview channel) ──────────────────────────────
+// ── The develop channel (GitFlow's preview channel) ───────────────────────────
//
-// Every push to the trunk republishes the six images under `:edge`, so a tester can run the next
+// Every push to the trunk republishes the six images under `:develop` — named after the branch
+// they are built from — so a tester can run the next
// release before it is a release. Mirrors the extension repo's rolling `preview` VSIX; the shape
// differs only because our artefact is a registry tag rather than a GitHub release asset.
//
@@ -53,16 +54,16 @@
// and rebuilding six multi-arch images because a markdown file changed is pure waste.
//
// Concurrency QUEUES rather than cancels (ConcurrencyCancelInProgress is left at its default
-// false): cancelling a push mid-way can leave `:edge` pointing at a half-written manifest list,
-// which is worse than an edge build running a few minutes behind.
+// false): cancelling a push mid-way can leave `:develop` pointing at a half-written manifest
+// list, which is worse than the channel running a few minutes behind the branch.
[GitHubActions(
- "publish-edge",
+ "publish-develop",
GitHubActionsImage.UbuntuLatest,
FetchDepth = 0,
OnPushBranches = new[] { DevelopBranch },
OnPushExcludePaths = new[] { "**/*.md", "docs/**" },
ConcurrencyGroup = "${{ github.workflow }}",
- InvokedTargets = new[] { nameof(PushEdge) },
+ InvokedTargets = new[] { nameof(PushDevelop) },
EnvironmentName = "ghcr",
ImportSecrets = new[] { nameof(RegistryUser), nameof(RegistryPassword) })]
@@ -100,7 +101,7 @@
//
// It also refuses to go out from the wrong branch: GitHubRelease asserts the tag is reachable from
// main or a support line (see Build.Release.cs). Under GitFlow the trunk is never tagged for
-// release — it ships through the edge channel instead.
+// release — it ships through the develop channel instead.
[GitHubActions(
"publish-release",
GitHubActionsImage.UbuntuLatest,
diff --git a/build/Build.Publish.cs b/build/Build.Publish.cs
index 678d20f..c6f514e 100644
--- a/build/Build.Publish.cs
+++ b/build/Build.Publish.cs
@@ -73,7 +73,7 @@ partial class Build
AbsolutePath ComposeDirectory => RootDirectory / ".artifacts" / "compose";
- /// Set by ; wins over every other tag resolution.
+ /// Set by ; wins over every other tag resolution.
string _tagOverride;
///
@@ -94,7 +94,7 @@ string EffectiveTag
{
get
{
- // An edge build runs off a branch, where the resolutions below would answer "dev" —
+ // A trunk build runs off a branch, where the resolutions below would answer "dev" —
// the point of the channel is that it has its own, stable, name.
if (!string.IsNullOrWhiteSpace(_tagOverride))
return _tagOverride;
@@ -208,16 +208,16 @@ string RemoteImage(string service) =>
PushImages();
});
- /// The rolling tag the trunk publishes under.
+ /// The rolling tag the trunk publishes under — named after the branch it comes from.
///
/// Not "latest": that name is conventionally the newest stable image, and a compose file
- /// left on the default tag would silently follow the trunk. Anyone running :edge has
- /// typed the word.
+ /// left on the default tag would silently follow the trunk. Anyone running :develop has
+ /// typed the name of a branch, which says exactly what they are getting.
///
- const string EdgeTag = "edge";
+ const string DevelopTag = "develop";
- Target PushEdge => _ => _
- .Description($"Push the rolling ':{EdgeTag}' images to GHCR — CI target for pushes to the trunk")
+ Target PushDevelop => _ => _
+ .Description($"Push the rolling ':{DevelopTag}' images to GHCR — CI target for pushes to the trunk")
.DependsOn(Compile)
.Requires(() => RegistryUser)
.Requires(() => RegistryPassword)
@@ -225,9 +225,9 @@ string RemoteImage(string service) =>
{
// The images are the whole channel — there is no separate release artefact to attach,
// as there would be for a versioned release. A tester points their existing .env at
- // :edge (docs/releasing.md#the-edge-channel) and pulls.
+ // :develop (docs/releasing.md#the-develop-channel) and pulls.
_targetRegistry = "ghcr.io";
- _tagOverride = EdgeTag;
+ _tagOverride = DevelopTag;
PushImages();
});
diff --git a/build/Build.Release.cs b/build/Build.Release.cs
index 20ab2fc..82ec89d 100644
--- a/build/Build.Release.cs
+++ b/build/Build.Release.cs
@@ -110,7 +110,7 @@ void AssertTagged() =>
///
///
///
- /// Under GitFlow the trunk is never tagged for release — develop ships through the edge
+ /// Under GitFlow the trunk is never tagged for release — develop ships through its own
/// channel, and a release comes from main after a stabilisation window
/// (docs/branching-and-release.md). Without this check that rule is documentation only, and
/// breaking it is silent: a v* tag anywhere publishes real images and a real release
@@ -149,7 +149,7 @@ void AssertReleasableRef()
Assert.True(releasable,
$"{ReleaseTag} is not reachable from origin/{MainBranch} or a support line — it is on " +
$"[{string.Join(", ", branches)}]. Releases are cut from {MainBranch}; the trunk ships " +
- "through the edge channel. See docs/branching-and-release.md.");
+ "through the develop channel. See docs/branching-and-release.md.");
Log.Information("{Tag} is reachable from {Branches}", ReleaseTag, string.Join(", ", branches));
}
diff --git a/docs/branching-and-release.md b/docs/branching-and-release.md
index d080fd1..79c7dc0 100644
--- a/docs/branching-and-release.md
+++ b/docs/branching-and-release.md
@@ -13,7 +13,7 @@ runs.
| Branch | Purpose | Lifetime | Tagged? |
|---|---|---|---|
-| `develop` | **Integration trunk. Default branch.** All finished work lands here first. Every push republishes the [`:edge` images](releasing.md#the-edge-channel). | Permanent | No |
+| `develop` | **Integration trunk. Default branch.** All finished work lands here first. Every push republishes the [`:develop` images](releasing.md#the-develop-channel). | Permanent | No |
| `main` | **Production.** Only receives merges from `release/*` and `hotfix/*`, and every one of those is tagged. Never committed to directly. | Permanent | **Yes** |
| `release/*` | **Stabilisation window** for a release being prepared. Cut from `develop`; takes only fixes and release prep. Merges to `main` *and back to* `develop`, then deleted. | Short-lived | No (the merge into `main` is) |
| `hotfix/*` | **Urgent production fix.** Cut from `main`. Merges to `main` *and* `develop`, then deleted. | Short-lived | No (the merge into `main` is) |
@@ -89,7 +89,7 @@ flowchart TD
A["A change needs to ship"] --> B{"Is a released version
broken right now?"}
B -->|No| C["feat/* or fix/*
off develop"]
C --> D["PR → develop"]
- D --> E["Ships on the next release
(and on :edge immediately)"]
+ D --> E["Ships on the next release
(and on :develop immediately)"]
B -->|Yes| F{"Does it affect the
version main is on?"}
F -->|Yes| G["hotfix/* off main"]
G --> H["PR → main, tag,
then merge back to develop"]
diff --git a/docs/ci.md b/docs/ci.md
index 0d54218..23e4d99 100644
--- a/docs/ci.md
+++ b/docs/ci.md
@@ -18,7 +18,7 @@ it.
| File | Trigger | Invokes | Environment |
|---|---|---|---|
| `build.yml` | push to `develop`/`main`; PR into `develop`, `main`, `release/*`, `hotfix/*`, `support/*` | `Test` — the required check | — |
-| `publish-edge.yml` | push to `develop` (non-docs) | `PushEdge` — rolling `:edge` images | `ghcr` |
+| `publish-develop.yml` | push to `develop` (non-docs) | `PushDevelop` — rolling `:develop` images | `ghcr` |
| `publish-ghcr.yml` | `v*` tag | `PushGhcr` — versioned multi-arch images | `ghcr` |
| `publish-release.yml` | `v*` tag | `GitHubRelease` — compose bundle + notes | `github-release` |
| `publish-dockerhub.yml` | dispatch only | `PushDockerHub` — mirror | `dockerhub` |
@@ -29,8 +29,8 @@ flowchart LR
B --> C(["ubuntu-latest ✓"])
D["Push to develop"] --> B
- D --> E["publish-edge.yml
PushEdge"]
- E --> ET["ghcr.io/…:edge"]
+ D --> E["publish-develop.yml
PushDevelop"]
+ E --> ET["ghcr.io/…:develop"]
T["Tag v* on main"] --> G["publish-ghcr.yml
PushGhcr"]
T --> R["publish-release.yml
GitHubRelease"]
@@ -63,7 +63,7 @@ The generator names a job after its runner image, so **all five workflows produc
In practice it only shows up in one place. A PR from a working branch has a head SHA that only the
gate ran on, so its check list is clean. A **release PR from `develop`** has a head SHA that
-`publish-edge` also ran on, so the PR lists the gate's check *and* the edge publish's, both under
+`publish-develop` also ran on, so the PR lists the gate's check *and* the edge publish's, both under
the same name — and GitHub requires every check with that name to pass.
That is a defensible thing to be blocked by (don't cut a release from a commit whose images
@@ -82,23 +82,24 @@ complements forever.
The extension repo pays that price because its gate packages a VSIX. Ours is a five-minute
`dotnet test`. We pay the five minutes.
-`publish-edge.yml` *does* filter paths, and safely: it is not a required check, so a skipped run
+`publish-develop.yml` *does* filter paths, and safely: it is not a required check, so a skipped run
blocks nothing.
-## publish-edge.yml — the trunk channel
+## publish-develop.yml — the trunk channel
Every non-docs push to `develop` rebuilds the six service images for `linux/amd64` and
-`linux/arm64` and pushes them to GHCR under `:edge`, replacing what was there. See
-[releasing.md](releasing.md#the-edge-channel) for how to run it.
+`linux/arm64` and pushes them to GHCR under `:develop`, replacing what was there. See
+[releasing.md](releasing.md#the-develop-channel) for how to run it.
Two deliberate choices worth knowing when reading the attribute:
- **Concurrency queues, never cancels.** `ConcurrencyCancelInProgress` stays at its default
- `false`. A cancelled push can leave `:edge` pointing at a half-written manifest list, which is
- worse than an edge image running a few minutes behind the trunk.
-- **`edge`, not `latest`.** `latest` is conventionally the newest *stable* image, and it is what a
- compose file falls back to when a tag is omitted — so naming the trunk channel `latest` would
- silently upgrade people who never asked for it. Anyone on `:edge` typed the word.
+ `false`. A cancelled push can leave `:develop` pointing at a half-written manifest list, which is
+ worse than the channel running a few minutes behind the branch.
+- **`develop`, not `latest`.** `latest` is conventionally the newest *stable* image, and it is what
+ a compose file falls back to when a tag is omitted — so naming the trunk channel `latest` would
+ silently upgrade people who never asked for it. Anyone on `:develop` typed the name of a branch,
+ which says exactly what they are getting.
## The tag pipeline
@@ -165,7 +166,7 @@ After changing any `[GitHubActions]` attribute:
```bash
./build.sh --generate-configuration GitHubActions_build --host GitHubActions
-./build.sh --generate-configuration GitHubActions_publish-edge --host GitHubActions
+./build.sh --generate-configuration GitHubActions_publish-develop --host GitHubActions
./build.sh --generate-configuration GitHubActions_publish-ghcr --host GitHubActions
./build.sh --generate-configuration GitHubActions_publish-release --host GitHubActions
./build.sh --generate-configuration GitHubActions_publish-dockerhub --host GitHubActions
diff --git a/docs/releasing.md b/docs/releasing.md
index 7e9edea..c8f4bd7 100644
--- a/docs/releasing.md
+++ b/docs/releasing.md
@@ -8,7 +8,7 @@ Channels, versioning, and the runbook for every kind of release. The branch mode
```mermaid
flowchart LR
- DEV["develop"] -->|every push| EDGE["ghcr.io/…:edge
rolling"]
+ DEV["develop"] -->|every push| EDGE["…:develop
rolling"]
MAIN["main / support/*"] -->|"v* tag"| GHCR["ghcr.io/…:0.3.0"]
MAIN -->|"v* tag"| REL["GitHub release
compose + env template"]
GHCR -.->|"manual dispatch"| DH["docker.io mirror"]
@@ -21,7 +21,7 @@ flowchart LR
| Channel | Trigger | Gating |
|---|---|---|
-| `:edge` images | every non-docs push to `develop` | none |
+| `:develop` images | every non-docs push to `develop` | none |
| versioned images + GitHub release | any `v*` tag reachable from `main`/`support/*` | the [release guard](ci.md#the-release-guard) |
| Docker Hub mirror | manual dispatch | manual by definition |
@@ -36,24 +36,25 @@ same string with the `v` stripped (`v0.3.0` → `:0.3.0`). Pre-1.0, so:
There is deliberately **no Nerdbank.GitVersioning here**, unlike the Fallout repos. They need a
computed monotonic version because every preview build publishes a numbered package to a registry
-that will not accept the same number twice. Our preview channel is a single rolling `:edge` tag with
+that will not accept the same number twice. Our preview channel is a single rolling `:develop` tag with
no number in it, so the machinery would buy nothing and cost a `version.json` to keep honest.
-## The edge channel
+## The develop channel
-Every non-docs push to `develop` republishes all six images under `:edge`. That is the whole
+Every non-docs push to `develop` republishes all six images under `:develop`, named after the branch
+they are built from. That is the whole
channel: no release object, no version, just the trunk in runnable form.
-To follow it, point an existing deployment's image tags at `edge`:
+To follow it, point an existing deployment's image tags at `develop`:
```bash
-sed -i '' 's/:[0-9]\+\.[0-9]\+\.[0-9]\+$/:edge/' .env # in a release bundle's .env
+sed -i '' 's/:[0-9]\+\.[0-9]\+\.[0-9]\+$/:develop/' .env # in a release bundle's .env
docker compose pull && docker compose up -d
```
-`:edge` moves under you — that is the point, and it is why the tag is not called `latest`. Expect a
+`:develop` moves under you — that is the point, and it is why the tag is not called `latest`. Expect a
schema migration to land there before it lands in a release; the Migrator runs to completion on
-every start, so an edge deployment upgrades itself, and **downgrading back to a release is not
+every start, so a develop deployment upgrades itself, and **downgrading back to a release is not
supported**. Take a database backup before following the trunk with data you care about.
## Cutting a release