Repository navigation
Migrate the remaining repos off the planning/ convention #67
Description
Activity
The recipe is missing a step:
release.ymldepends onplanning/Found while migrating
modern-di-pytest(the first off this checklist). Step 8 covers
justfileand CI'scheck-planning/index, but not the release workflow — and in the
_checks.yml-convention repos that workflow readsplanning/directly:notes="planning/releases/${GITHUB_REF_NAME}.md" if [ ! -f "$notes" ]; then echo "::error::Stable tag ${GITHUB_REF_NAME} has no curated release notes at ${notes}..." exit 1 fi
It does two things: hard-requires a curated notes file for every stable tag, and sources the
GitHub Release body from it. Deleteplanning/while leaving that in place and the next
stable tag fails the release job — afterjust publishhas already pushed to PyPI, since
the notes gate runs before publish but the body resolution runs after.This is not one repo's quirk. Spot-checked locally:
lite-bootstrap— same threeplanning/releases/references inrelease.ymlmodern-di-faststream— same threechat-app— different shape:main.ymlinvokesplanning/index.pyandplanning/links.py
directly (relevant to chat-app is half-migrated: the PR body is the spec, but planning/ is still a merge gate #70)
There is already a precedent to copy.
modern-dihit this during its own migration and
resolved it in1ea74ee, "drop theplanning/directory and the curated-release-notes
convention" (modern-python/modern-di#449) — one of the five PRs this issue cites. Its
post-migrationrelease.ymldrops the notes gate and the body source, keeping only the
prerelease flag:- name: Publish GitHub Release uses: softprops/action-gh-release@v3 with: generate_release_notes: true prerelease: ${{ steps.meta.outputs.prerelease }} draft: false
Suggested step 8b:
release.ymldrops the curated-notes gate and the
planning/releases/<tag>.mdbody source, matchingmodern-dipost-1ea74ee. Worth calling
out explicitly that this retires a stated policy — curated notes were mandatory for stable
tags — so a migration PR should say so rather than let it ride in as a docs change. That also
means a migrating repo's PR ischore:, notdocs:: it changes release behaviour.One more note for whoever picks up the remaining repos:
planning/releases/*.mdare
byte-identical to the published GitHub Release bodies (checked onmodern-di-pytest3.0.1), so
deleting them loses nothing — the Releases are the record.- added 13 commits that reference this issue
on Sep 6, 2026 23 remaining items
- added 15 commits that reference this issue
on Sep 6, 2026
Tracking issue for moving the rest of the org off the
planning/convention and ontoPR-body-as-spec. #50 did this repo;
modern-diandfaststream-outboxdid themselvesearlier. This covers everyone else.
Where the org actually stands
Measured across all 28 non-archived repos, not estimated:
CONTEXT.md+docs/adr/, noplanning/.github,modern-di,faststream-outboxchat-appplanning/onlythat-depends,fastapi-sqlalchemy-template,litestar-sqlalchemy-templateThree of those are handled elsewhere and are not part of this issue's checklist:
chat-app— chat-app is half-migrated: the PR body is the spec, but planning/ is still a merge gate #70that-depends— that-depends has no agent instructions file #69fastapi-sqlalchemy-templateandlitestar-sqlalchemy-templateare on neitherconvention and have no
planning/tree, so there is nothing here to migrate. Whetherthey should adopt one is undecided and untracked.
Why this is a programme, not a sweep
The
.githubmigration (#50) was one PR but a session of judgment: ruling on 24 changefiles, one decision record, a deferred list, and a 5-page
architecture/tree — each oneeither derivable and dropped, enforceable and turned into a test, a rejected alternative
turned into an ADR, or real work turned into an issue.
modern-ditook five PRs(modern-python/modern-di#424, #432, #433, #439, #449).
Per-repo issues should be spawned as work starts, not written upfront — 21 stale specs
would be worse than none.
The recipe, as actually performed twice
CONTEXT.md— the vocabulary. Seed fromarchitecture/glossary.mdwhere one exists;otherwise author it, and audit every
_Avoid_entry against real usage before committing(in
.githubthat cut ten terms to seven — four rejected synonyms appeared nowhere inthe repo).
docs/adr/—planning/decisions/*becomeNNNN-slug.md, each with a revisittrigger. Also rescue rejected alternatives buried in change files and capability pages.
planning/changes/*are deleted. Git history is the record; route anythingload-bearing through the admission check first.
architecture/is dropped. Enforceable claims become tests whose name is the claim,with an
INVARIANT:docstring naming what breaks it.AGENTS.mdgains the Workflow and Where-a-fact-goes sections and loses the lanes.docs/agents/domain.mdrepoints toCONTEXT.md+docs/adr/.justfileand CI dropcheck-planning/index. Add the offline link gate (Add the offline link gate to the 18 green repos, and unpublish the ADRs in the two that have them #66) inthe same PR — see below.
.github/PULL_REQUEST_TEMPLATE.md. The org default is staying as thegeneric form and is true under either convention, so a migrating repo needs no template
change. Template work is Delete the local PR templates; keep the generic org default #53, which runs independently of this issue.
The link gate rides along
#66 adopts a blocking offline link check in the 18 repos that are already green. Seven
repos are red, and all seven are red only inside
planning/:httpware 56, lite-bootstrap 8, compose2pod 4, semvertag 3, faststream-concurrent-aiokafka 3,
faststream-redis-timers 2, db-retry 1 — 77 broken links, 77 of 77 in
planning/, zero inany user-facing surface.
Deleting
planning/deletes all 77. So each migration PR should add the gate as its laststep and land green, rather than #66 excluding
planning/to work around history that isabout to be removed.
Checklist — the 21 not-migrated repos
compose2pod(4 dead links) — chore: migrate off the planning/ convention compose2pod#89db-retry(1) — chore: migrate off the planning/ convention db-retry#37eof-fixer— chore: migrate off the planning/ convention eof-fixer#34faststream-concurrent-aiokafka(3) — chore: migrate off the planning/ convention faststream-concurrent-aiokafka#65faststream-redis-timers(2) — chore: migrate off the planning/ convention faststream-redis-timers#68httpware(56) — chore: migrate off the planning/ convention httpware#119lite-bootstrap(8) — chore: migrate off the planning/ convention lite-bootstrap#176modern-di-aiogram— chore: migrate off the planning/ convention modern-di-aiogram#14modern-di-aiohttp— chore: migrate off the planning/ convention modern-di-aiohttp#19modern-di-arq— chore: migrate off the planning/ convention modern-di-arq#14modern-di-celery— chore: migrate off the planning/ convention modern-di-celery#14modern-di-fastapi— chore: migrate off the planning/ convention modern-di-fastapi#42modern-di-faststream— chore: migrate off the planning/ convention modern-di-faststream#43modern-di-flask— chore: migrate off the planning/ convention modern-di-flask#14modern-di-grpc— chore: migrate off the planning/ convention modern-di-grpc#13modern-di-litestar— chore: migrate off the planning/ convention modern-di-litestar#44modern-di-pytest— chore: migrate off the planning/ convention modern-di-pytest#40modern-di-starlette— chore: migrate off the planning/ convention modern-di-starlette#19modern-di-taskiq— chore: migrate off the planning/ convention modern-di-taskiq#12modern-di-typer— chore: migrate off the planning/ convention modern-di-typer#37semvertag— chore: migrate off the planning/ convention semvertag#62chat-app(#70) andthat-depends(#69) are tracked separately and are not on this list.Out of scope