Skip to content
38 changes: 35 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,9 +501,41 @@ PR-triggered check on the existing Lint workflow — **no new cron/scheduled wor
in another repo, which no PR in this repo can make, so failing would only turn unrelated PRs red. It
mirrors the N-1 rule (the same lag in the other direction), which is also accepted and flagged.
- **Only a file that matches no standards emission is DRIFTED**, and that still fails.
- **A comparison that cannot be made is said so.** If the standards HEAD commit or its emission cannot
be read, the file stays DRIFTED and fails, but the row is tagged `ahead-unchecked` and the message
tells you to re-run with `STANDARDS_REF=<standards main commit>` before re-seeding.
- **HEAD is compared only when it is newer (#2237).** A SHA that differs from HEAD does not prove HEAD
is newer: an explicit `STANDARDS_REF` can name a standards branch that is not in `main`'s history. So
the AHEAD comparison runs only when the baseline commit is an ancestor of the standards HEAD. This is
read once per run from the compare API. A baseline that is ahead of HEAD or diverged from it never
yields AHEAD; a `::notice::` says why.
- **A comparison that cannot be made is said so.** If the standards HEAD commit, its relation to the
baseline, or its emission cannot be read, the file stays DRIFTED and fails. The row is tagged
`ahead-unchecked`, and the message tells you to re-run with `STANDARDS_REF=<standards main commit>`
before re-seeding.
- **A file may also match a commit between the channel and HEAD (#2237).** The comparison checks only
the channel and HEAD, so a template synced from a standards commit between them is still DRIFTED.
When HEAD is newer than the channel, the DRIFTED message does not give the bare "Re-seed it" remedy.
It says an intermediate-commit sync is possible and how to check it: re-run with
`STANDARDS_REF=<commit>` for the commits in that range that touched the file's source. If one reports
ALIGNED, re-seed at standards HEAD and promote standards. Never re-seed from the channel.
- **Decision: a message, not detection.** To match intermediate commits, the guard would need each
file's standards source paths, which only `seed-repo-template.sh` knows. It would also need one
commits-list call per DRIFTED file and one emission per commit in the range. That adds network
cost to every PR's lint run. The message removes the wrong advice without that cost.

- **Seeding is an operator procedure with recorded provenance (#1925).** No workflow runs
`seed-repo-template.sh`. An operator follows
[`docs/release/seeding-repo-template.md`](./docs/release/seeding-repo-template.md): dry run first, leave
`STANDARDS_REF` unset so the published channel is used.
- **Provenance.** Every seed PR body states the resolved standards ref, how it was chosen (channel,
explicit, HEAD fallback or local) and the commit. A reused PR's body is rewritten on each run.
- **One seed PR.** An open `seed-scaffold/*` PR is updated in place (#2233). If several are open, the
newest is kept and each older one is closed with a comment linking it. A PR that cannot be closed
fails the run.
- **No downgrades.** A file that differs from the run's emission but matches the emission at standards
HEAD is **refused**, with "standards channel is behind the template — promote standards". This is the
seed-side twin of the drift guard's AHEAD status and reuses its HEAD and ancestry reads. If every
differing file is refused, no PR is opened.
- **Cannot check means stop.** If the HEAD commit, its relation to the resolved ref, or the HEAD emission
cannot be read, the seed aborts instead of overwriting the file.

- **Reference rows — `agent-ingress.yml` (#1729, AC #12):** `.github/workflows/agent-ingress.yml` is
enrolled in the drift manifest for **post-collapse byte-identity coverage**, but
Expand Down
90 changes: 90 additions & 0 deletions docs/release/seeding-repo-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Seeding `repo-template` — operator procedure

`scripts/seed-repo-template.sh` writes the org baseline scaffold into
`petry-projects/repo-template` and opens one pull request there. No workflow runs
it. An operator runs it by hand, following this procedure, so the standards ref a
seed is generated from is predictable (#1925).

For what the scaffold contains and why the template must track standards, see
[AGENTS.md → Template drift guard](../../AGENTS.md#template-drift-guard-repo-template).

## When to seed

- After the standards channel is promoted (`standards/v1-stable` moved), so the
template picks up the newly published content.
- When `template-drift` reports a file **DRIFTED** or **MISSING**.

Do **not** seed when `template-drift` reports **AHEAD**. The template already
carries newer standards content than the channel. Promote standards instead
(`scripts/cut-standards-release.sh` in `petry-projects/.github`).

## Before you start

- Run from a checkout of this repo at `main`.
- Run on Linux, or on macOS with GNU bash 5 and coreutils first on `PATH`. Stock
macOS bash 3.2 cannot run the script.
- `gh` must be logged in with write access to `petry-projects/repo-template`.

## Which standards ref

Leave `STANDARDS_REF` unset. The script then resolves the published channel
`standards/v1-stable` and pins every read to that commit.

Set `STANDARDS_REF` only to reproduce or investigate a specific seed. Never set it
to seed the template ahead of the channel: the next channel-based seed would then
be a downgrade, which the script refuses.

## Steps

1. **Dry run.** It reads only and prints one decision per file.

```bash
DRY_RUN=true bash scripts/seed-repo-template.sh --repo petry-projects/repo-template
```

2. **Read the plan.** Check the `standards ref:` line names the ref and commit you
expect, then check each file's decision:

| Decision | Meaning |
|---|---|
| `CREATE` / `UPDATE` | The file will be written. |
| `REPLACE … DESTRUCTIVE` | The file will be written and gets shorter. Look at why before going on. |
| `SKIP` | Already identical. |
| `PRESERVE` | Owned by the consumer or by another managed process. Left alone. |
| `REFUSE` | The template is ahead of the ref. Left alone. See below. |

3. **Seed.**

```bash
bash scripts/seed-repo-template.sh --repo petry-projects/repo-template
```

4. **Review the pull request** it opens or updates on `repo-template`, then merge it
there.

## What the run does with pull requests

- **One seed PR per repo.** If a `seed-scaffold/*` PR is already open, the run
updates that PR's branch instead of opening another.
- **Older seed PRs are closed.** If several are open, the newest is kept. Each older
one is closed with a comment linking the kept PR. If one cannot be closed, the run
fails and names it.
- **The PR body states the provenance:** the resolved standards ref, how it was
chosen (channel, explicit `STANDARDS_REF`, HEAD fallback, or a local
`STANDARDS_DIR`), and the commit. A reused PR's body is rewritten on each run.
- **No PR for nothing.** If no file needs writing, no PR is opened.

## `REFUSE`: the standards channel is behind the template

A file is refused when it differs from this run's emission but matches the emission
at the standards default-branch HEAD. Writing the channel's version over it would
downgrade the template. The run leaves the file alone and warns:

> standards channel is behind the template — promote standards

Promote the channel, then seed again. If every differing file is refused, no PR is
opened.

If the script cannot tell whether a newer standards commit exists, or cannot compute
the emission at HEAD, it stops with an error instead of overwriting the file. Fix the
read (usually a `gh` login or rate-limit problem) and run it again.
Loading
Loading