|
| 1 | +# Planning — modern-python/.github |
| 2 | + |
| 3 | +This repo's planning home, following the portable two-axis convention from |
| 4 | +[`lesnik512/planning-convention`](https://github.com/lesnik512/planning-convention) |
| 5 | +(applied version in [`.convention-version`](.convention-version)). `architecture/` |
| 6 | +(repo root) holds the living truth about what the system does now; the bundles in |
| 7 | +[`changes/`](changes/) record how it got there. To update the convention itself, |
| 8 | +re-run that repo's `APPLY.md` flow. |
| 9 | + |
| 10 | +## Quick path (start here) |
| 11 | + |
| 12 | +> The fast lane for making a change. The full reference is in |
| 13 | +> [Conventions](#conventions) below — read it only when this isn't enough. |
| 14 | +
|
| 15 | +**1. Choose a lane — first matching rule wins:** |
| 16 | + |
| 17 | +1. Any of: needs design judgment · new file/module · public-API change · |
| 18 | + cross-cutting or multi-file · non-trivial test design → **Full** |
| 19 | + (`design.md` + `plan.md`) |
| 20 | +2. Purely mechanical: typo · dep bump · linter/formatter/CI tweak · |
| 21 | + mechanical rename · single-line config → **Tiny** (no bundle, conventional |
| 22 | + commit) |
| 23 | +3. Small-but-real, none of the above: ≲30 LOC net · ≤2 files · no new file · |
| 24 | + no public-API change · one straightforward test → **Lightweight** |
| 25 | + (`change.md`) |
| 26 | + |
| 27 | +Ambiguous between two? Take the heavier. A `change.md` that outgrows its lane |
| 28 | +splits into `design.md` + `plan.md`. |
| 29 | + |
| 30 | +**2. Create the bundle** (Full / Lightweight only): |
| 31 | +`planning/changes/YYYY-MM-DD.NN-<slug>/`, where `.NN` is a zero-padded |
| 32 | +intra-day counter. Copy the matching template from |
| 33 | +[`_templates/`](_templates/). |
| 34 | + |
| 35 | +**3. Ship in the implementing PR:** hand-edit the affected |
| 36 | +`architecture/<capability>.md`, finalize the bundle's `summary:` to the |
| 37 | +realized result, and run `just check-planning` before pushing. |
| 38 | + |
| 39 | +## Conventions |
| 40 | + |
| 41 | +> This is the portable convention, sourced from the canonical repo |
| 42 | +> [`lesnik512/planning-convention`](https://github.com/lesnik512/planning-convention) |
| 43 | +> (applied version in [`.convention-version`](.convention-version)). To update |
| 44 | +> it, run that repo's `APPLY.md` flow. The generated change index (`just index`) |
| 45 | +> and the `## Other` pointers below are repo-local. |
| 46 | +
|
| 47 | +### Two axes, never mixed |
| 48 | + |
| 49 | +- **`architecture/` (repo root) — the present.** One file per capability, plus |
| 50 | + a single `glossary.md` (the ubiquitous language); living prose, updated in the |
| 51 | + same PR that ships the change. The truth home. |
| 52 | +- **`planning/changes/` — the past-and-pending.** One folder per change, |
| 53 | + kept in place after ship. |
| 54 | + |
| 55 | +A change **promotes** its conclusions into the affected |
| 56 | +`architecture/<capability>.md` by hand **in the implementing PR, alongside the |
| 57 | +code** — the edit rides in the same diff and is reviewed with it, never applied |
| 58 | +as a separate post-merge step. That hand-edit is what keeps `architecture/` |
| 59 | +true; the bundle stays in `changes/` as the *why*. |
| 60 | + |
| 61 | +### Glossary |
| 62 | + |
| 63 | +`architecture/glossary.md` is the project's **ubiquitous language** — one page |
| 64 | +defining the domain terms that code, specs, and capability pages all share. Like |
| 65 | +the capability files beside it, it is living prose with **no frontmatter**, dated |
| 66 | +by git, and authored lazily: it appears when the first term is worth pinning down. |
| 67 | + |
| 68 | +Each entry is a term, a one-or-two-sentence definition of what it *is* (not what |
| 69 | +it does), and an optional `_Avoid_:` line naming the synonyms to reject: |
| 70 | + |
| 71 | +```md |
| 72 | +**Timer**: |
| 73 | +A scheduled future delivery, identified by a timer id. |
| 74 | +_Avoid_: job, task, alarm |
| 75 | +``` |
| 76 | + |
| 77 | +Keep it a glossary, not a spec — no implementation detail. A change that |
| 78 | +introduces or sharpens a term updates `glossary.md` in the same PR, the same way |
| 79 | +a behavior change promotes into a capability file. |
| 80 | + |
| 81 | +### Change bundles |
| 82 | + |
| 83 | +A change is a folder `changes/YYYY-MM-DD.NN-<slug>/`: |
| 84 | + |
| 85 | +- `YYYY-MM-DD` — proposal date; `.NN` — zero-padded intra-day counter |
| 86 | + (`.01`, `.02`, …) that breaks same-date ties so the timeline sorts stably. |
| 87 | +- `<slug>` — kebab-case description, not a story ID. |
| 88 | + |
| 89 | +`summary` is written when the change is created (the intent one-liner) and |
| 90 | +**finalized at ship** to state the realized result — set in the implementing |
| 91 | +PR, alongside the code and the `architecture/` promotion. No post-merge |
| 92 | +bookkeeping, no folder move. `date` and `slug` are never written — they are |
| 93 | +read from the bundle's directory name. |
| 94 | + |
| 95 | +### Three lanes |
| 96 | + |
| 97 | +| Lane | Artifacts | Use when | |
| 98 | +|------|-----------|----------| |
| 99 | +| **Full** | `design.md` + `plan.md` | design judgment; new file/module; public-API change; cross-cutting/multi-file; non-trivial test design | |
| 100 | +| **Lightweight** | `change.md` | small-but-real: ≲30 LOC net, ≤2 files, no new file, no public-API change, single straightforward test | |
| 101 | +| **Tiny** | none — conventional commit | typo, dep bump, linter/formatter/CI tweak, mechanical rename, single-line config | |
| 102 | + |
| 103 | +Heavier lane wins on ambiguity. A `change.md` that outgrows its lane splits |
| 104 | +into `design.md` + `plan.md`. |
| 105 | + |
| 106 | +### Artifacts at a glance |
| 107 | + |
| 108 | +- **`design.md`** — the spec: the *thinking* (why, design, trade-offs, scope). |
| 109 | +- **`plan.md`** — the plan: the *sequencing* (the executor's task checklist). |
| 110 | +- **`change.md`** — both, condensed, for the lightweight lane. |
| 111 | +- **`releases/<semver>.md`** — per-release user-facing notes. |
| 112 | +- **`audits/<date>-<slug>.md`** — findings from a code/docs/bug-hunt sweep; |
| 113 | + spawns fix changes. |
| 114 | +- **`retros/<date>-<slug>.md`** — what we learned after a body of work. |
| 115 | +- **`deferred.md`** — real-but-unscheduled items, each with a revisit trigger. |
| 116 | +- **`decisions/<YYYY-MM-DD>-<slug>.md`** — one file per design decision taken |
| 117 | + (especially options *rejected*), each with a revisit trigger; listed by |
| 118 | + `just index`. |
| 119 | + |
| 120 | +Templates live in [`_templates/`](_templates/). |
| 121 | + |
| 122 | +### Frontmatter |
| 123 | + |
| 124 | +`date` and `slug` are **derived from the directory / file name** — never |
| 125 | +repeated in frontmatter. So: |
| 126 | + |
| 127 | +- `design.md` / `change.md`: `summary` (single line) only. |
| 128 | +- `plan.md`: **no frontmatter** — its identity is the bundle directory. |
| 129 | +- `decisions/*.md`: `status` (accepted|superseded), `summary`, and optional |
| 130 | + `supersedes` / `superseded_by`. |
| 131 | +- Files in `architecture/` carry **no** frontmatter — living prose, dated by git. |
| 132 | + |
| 133 | +**`summary`** is one line: written at creation as the intent, then **finalized |
| 134 | +at ship** to state the realized result — what shipped and its effect. It is the |
| 135 | +only field the index renders. |
| 136 | + |
| 137 | +## Index |
| 138 | + |
| 139 | +Run `just index` to print the change/decision listing — a query over the files, |
| 140 | +never a committed artifact. |
| 141 | + |
| 142 | +## Other |
| 143 | + |
| 144 | +- [`launch-playbook.md`](launch-playbook.md) — internal Phase 4 launch asset (not published). |
| 145 | +- [`deferred.md`](deferred.md) — real-but-unscheduled items, each with a revisit trigger. |
0 commit comments