Skip to content
25 changes: 25 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,31 @@ PR-triggered check on the existing Lint workflow — **no new cron/scheduled wor
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.

- **`seed-repo-template.sh` has one home: this repo (#1927).** `petry-projects/.github` once carried a
different, smaller script under the same name, and the two were mistaken for diverged copies. That
script only prints one standard file from a local checkout and is now `scripts/emit-standard-file.sh`
there; a CI guard in that repo fails if a `seed-repo-template.sh` reappears. Change the seeder here.

- **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. If the channel cannot be resolved the script
falls back to standards HEAD and reports `source head-fallback`; the operator stops there.
- **Provenance.** Every seed PR body states the resolved standards ref, how it was chosen (channel,
explicit, HEAD fallback or local) and the commit. Files are fetched at that commit, not through the
ref name. A local `STANDARDS_DIR` has no commit, so the body records `unknown`. 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. If the open PRs cannot be listed, the run stops before it writes anything.
- **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. A local `STANDARDS_DIR` has no ref, so this check does
not run there; do not use it for a real seed.
- **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
`seed-repo-template.sh` deliberately never seeds it (it lives in the `--emit-workflow`-only
Expand Down
103 changes: 103 additions & 0 deletions docs/release/seeding-repo-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# 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.

If the channel cannot be resolved, the script falls back to the standards
default-branch HEAD and says so: the `standards ref:` line shows
`source head-fallback`. Stop there. A fallback seed is not a channel seed, so do
not go on to step 3 until the channel resolves.

Do not set `STANDARDS_DIR` for a real seed. It reads a local checkout, which has
no ref and no commit: the PR body then records the commit as `unknown`, and the
no-downgrade check below cannot run. It exists for tests.

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 and shows `source channel`, 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 (`unknown` for a local `STANDARDS_DIR`). Every
file is fetched at that commit, not through the ref name, so the content and the
recorded commit cannot come apart. A reused PR's body is rewritten on each run.
- **An unreadable PR list stops the run.** If the open pull requests cannot be
listed, the script does not seed, because it could not rule out an open seed PR.
- **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