Skip to content

Commit cd41771

Browse files
authored
chore: adopt canonical planning convention (#16)
* chore: adopt canonical planning convention Fresh-adopt the portable two-axis planning convention from lesnik512/planning-convention (v1.0.0): - Vendor planning/index.py (validator + index generator) and planning/_templates/ (change, design, plan, decision, release). - Add planning/README.md with the Quick path + Conventions prose and planning/.convention-version (1.0.0); scaffold changes/, decisions/, releases/ directories. - Add architecture/README.md as the per-capability truth home with the promotion rule (no capability files yet — repo authors its own). - Wire `uv run python planning/index.py --check` into `lint-ci`; add `index` and `check-planning` recipes to the Justfile. - Point CLAUDE.md § Workflow at planning/README.md's Quick path and add the architecture promotion reminder. just lint-ci green (ruff + ty + planning validator); check-planning: OK. * index.py: tolerate a missing changes/ dir (sync canonical fix)
1 parent cc1c6a9 commit cd41771

11 files changed

Lines changed: 553 additions & 7 deletions

File tree

CLAUDE.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
## Workflow
22

3-
Per-feature workflow: brainstorming → spec in
4-
`planning/specs/YYYY-MM-DD-<slug>-design.md` → writing-plans →
5-
plan in `planning/plans/YYYY-MM-DD-<slug>-plan.md`
6-
executing-plans / subagent-driven-development →
7-
requesting-code-review → finishing-a-development-branch.
3+
Planning uses a portable convention — `architecture/` (repo root) is the living
4+
**truth home** and promotion target; `planning/changes/` holds the per-change
5+
bundles. Start at the
6+
[Quick path](planning/README.md#quick-path-start-here) in `planning/README.md`
7+
(the authoritative spec) to pick a lane — **Full** (`design.md` + `plan.md`),
8+
**Lightweight** (single `change.md`), or **Tiny** (just a commit) — and ship.
9+
`just check-planning` validates bundles; `just index` prints the change +
10+
decision listing; `planning/_templates/` are copy-and-fill starting points.
811

9-
Topic slugs are kebab-case descriptions (e.g. `faststream-0.7-migration`),
10-
not story IDs.
12+
**When a change alters a capability's behavior, update the matching
13+
`architecture/<capability>.md` in the same PR** — that promotion is what keeps
14+
`architecture/` true.

Justfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ lint-ci:
1515
uv run ruff format --check
1616
uv run ruff check --no-fix
1717
uv run ty check
18+
uv run python planning/index.py --check
19+
20+
# Print the planning change index (flat, newest-first) to stdout.
21+
index:
22+
uv run python planning/index.py
23+
24+
# Validate planning bundles + decisions; CI runs this.
25+
check-planning:
26+
uv run python planning/index.py --check
1827

1928
test *args:
2029
uv run --no-sync pytest {{ args }}

architecture/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Architecture
2+
3+
The living truth about what `modern-di-faststream` does **now** — one file per
4+
capability, updated by hand whenever a change ships. The *why* and *how it got
5+
here* live in [`../planning/changes/`](../planning/changes/), and decisions
6+
deliberately taken (including options rejected) in
7+
[`../planning/decisions/`](../planning/decisions/); this directory is the present.
8+
9+
Each capability file is an **implementation-detail** page. Its terse
10+
**invariant summary** ("what Claude must not break") lives in
11+
[`../CLAUDE.md`](../CLAUDE.md) § Architecture.
12+
13+
These files carry **no frontmatter** — they are prose, dated by git.
14+
15+
## Capabilities
16+
17+
_None yet — the repo authors its own capability files as changes ship._
18+
19+
## Promotion rule
20+
21+
Shipping a change hand-edits the affected capability file(s) here to match the
22+
new reality, in the same PR as the code. The change bundle stays in place under
23+
[`../planning/changes/`](../planning/changes/) — no folder move.

planning/.convention-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.0.0

planning/README.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Planning
2+
3+
Specs, plans, and change history for `modern-di-faststream`. The living truth
4+
about *what the system does now* lives in [`architecture/`](../architecture/)
5+
at the repo root; this directory records *how it got there*.
6+
7+
## Quick path (start here)
8+
9+
> The fast lane for making a change. The full reference is in
10+
> [Conventions](#conventions) below — read it only when this isn't enough.
11+
12+
**1. Choose a lane — first matching rule wins:**
13+
14+
1. Any of: needs design judgment · new file/module · public-API change ·
15+
cross-cutting or multi-file · non-trivial test design → **Full**
16+
(`design.md` + `plan.md`)
17+
2. Purely mechanical: typo · dep bump · linter/formatter/CI tweak ·
18+
mechanical rename · single-line config → **Tiny** (no bundle, conventional
19+
commit)
20+
3. Small-but-real, none of the above: ≲30 LOC net · ≤2 files · no new file ·
21+
no public-API change · one straightforward test → **Lightweight**
22+
(`change.md`)
23+
24+
Ambiguous between two? Take the heavier. A `change.md` that outgrows its lane
25+
splits into `design.md` + `plan.md`.
26+
27+
**2. Create the bundle** (Full / Lightweight only):
28+
`planning/changes/YYYY-MM-DD.NN-<slug>/`, where `.NN` is a zero-padded
29+
intra-day counter. Copy the matching template from
30+
[`_templates/`](_templates/).
31+
32+
**3. Ship in the implementing PR:** hand-edit the affected
33+
`architecture/<capability>.md`, finalize the bundle's `summary:` to the
34+
realized result, and run `just check-planning` before pushing.
35+
36+
## Conventions
37+
38+
> This is the portable convention, sourced from the canonical repo
39+
> [`lesnik512/planning-convention`](https://github.com/lesnik512/planning-convention)
40+
> (applied version in [`.convention-version`](.convention-version)). To update
41+
> it, run that repo's `APPLY.md` flow. The generated change index (`just index`)
42+
> and the `## Other` pointers below are repo-local.
43+
44+
### Two axes, never mixed
45+
46+
- **`architecture/` (repo root) — the present.** One file per capability,
47+
living prose, updated in the same PR that ships the change. The truth home.
48+
- **`planning/changes/` — the past-and-pending.** One folder per change,
49+
kept in place after ship.
50+
51+
A change **promotes** its conclusions into the affected
52+
`architecture/<capability>.md` by hand **in the implementing PR, alongside the
53+
code** — the edit rides in the same diff and is reviewed with it, never applied
54+
as a separate post-merge step. That hand-edit is what keeps `architecture/`
55+
true; the bundle stays in `changes/` as the *why*.
56+
57+
### Change bundles
58+
59+
A change is a folder `changes/YYYY-MM-DD.NN-<slug>/`:
60+
61+
- `YYYY-MM-DD` — proposal date; `.NN` — zero-padded intra-day counter
62+
(`.01`, `.02`, …) that breaks same-date ties so the timeline sorts stably.
63+
- `<slug>` — kebab-case description, not a story ID.
64+
65+
`summary` is written when the change is created (the intent one-liner) and
66+
**finalized at ship** to state the realized result — set in the implementing
67+
PR, alongside the code and the `architecture/` promotion. No post-merge
68+
bookkeeping, no folder move. `date` and `slug` are never written — they are
69+
read from the bundle's directory name.
70+
71+
### Three lanes
72+
73+
| Lane | Artifacts | Use when |
74+
|------|-----------|----------|
75+
| **Full** | `design.md` + `plan.md` | design judgment; new file/module; public-API change; cross-cutting/multi-file; non-trivial test design |
76+
| **Lightweight** | `change.md` | small-but-real: ≲30 LOC net, ≤2 files, no new file, no public-API change, single straightforward test |
77+
| **Tiny** | none — conventional commit | typo, dep bump, linter/formatter/CI tweak, mechanical rename, single-line config |
78+
79+
Heavier lane wins on ambiguity. A `change.md` that outgrows its lane splits
80+
into `design.md` + `plan.md`.
81+
82+
### Artifacts at a glance
83+
84+
- **`design.md`** — the spec: the *thinking* (why, design, trade-offs, scope).
85+
- **`plan.md`** — the plan: the *sequencing* (the executor's task checklist).
86+
- **`change.md`** — both, condensed, for the lightweight lane.
87+
- **`releases/<semver>.md`** — per-release user-facing notes.
88+
- **`audits/<date>-<slug>.md`** — findings from a code/docs/bug-hunt sweep;
89+
spawns fix changes.
90+
- **`retros/<date>-<slug>.md`** — what we learned after a body of work.
91+
- **`deferred.md`** — real-but-unscheduled items, each with a revisit trigger.
92+
- **`decisions/<YYYY-MM-DD>-<slug>.md`** — one file per design decision taken
93+
(especially options *rejected*), each with a revisit trigger; listed by
94+
`just index`.
95+
96+
Templates live in [`_templates/`](_templates/).
97+
98+
### Frontmatter
99+
100+
`date` and `slug` are **derived from the directory / file name** — never
101+
repeated in frontmatter. So:
102+
103+
- `design.md` / `change.md`: `summary` (single line) only.
104+
- `plan.md`: **no frontmatter** — its identity is the bundle directory.
105+
- `decisions/*.md`: `status` (accepted|superseded), `summary`, and optional
106+
`supersedes` / `superseded_by`.
107+
- Files in `architecture/` carry **no** frontmatter — living prose, dated by git.
108+
109+
**`summary`** is one line: written at creation as the intent, then **finalized
110+
at ship** to state the realized result — what shipped and its effect. It is the
111+
only field the index renders.
112+
113+
## Index
114+
115+
The listing is **generated**, not maintained — run `just index` to print it: a
116+
flat, newest-first list of changes, then decisions newest-first. The frontmatter
117+
in each bundle / decision file is the single source of truth; there is no
118+
committed copy to drift.
119+
120+
## Other
121+
122+
- **[`architecture/`](../architecture/)** at the repo root — the living
123+
capability truth. This is the promotion target on every ship.
124+
- **[decisions/](decisions/)** — design decisions taken (and alternatives
125+
rejected), each with a revisit trigger, so reviews don't re-litigate them;
126+
indexed by `just index`.
127+
- **[specs/](specs/)** — pre-convention design docs retained for history (e.g.
128+
the FastStream 0.7 migration design).

planning/_templates/change.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
summary: One line — shown in the generated index. Written at creation; finalize at ship to state the realized result.
3+
---
4+
5+
# Change: One-line capitalized title
6+
7+
**Lane:** lightweight — ≲30 LOC net, ≤2 files, no new file, no public-API
8+
change, a single straightforward test. If it outgrows this, split into
9+
`design.md` + `plan.md`.
10+
11+
## Goal
12+
13+
One or two sentences: what changes and why.
14+
15+
## Approach
16+
17+
The shape of the change in brief — enough that a reviewer sees the design
18+
without a full spec. Link the truth home (`architecture/<capability>.md`) if a
19+
capability contract moves.
20+
21+
## Files
22+
23+
- `path/to/file.py` — what changes
24+
- `tests/test_x.py` — test added / updated
25+
26+
## Verification
27+
28+
- [ ] Failing test first — command + expected error.
29+
- [ ] Apply the change.
30+
- [ ] Test passes — command.
31+
- [ ] `just test` — full suite green.
32+
- [ ] `just lint` — clean.

planning/_templates/decision.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
status: accepted # accepted | superseded
3+
summary: One line — shown in `just index`.
4+
supersedes: null
5+
superseded_by: null
6+
---
7+
8+
# One-line capitalized title
9+
10+
**Decision:** What was decided, in a sentence.
11+
12+
## Context
13+
14+
Why this came up; the options that were on the table.
15+
16+
## Decision & rationale
17+
18+
The call and why — including why the alternatives were rejected. Enough that a
19+
future explorer doesn't re-litigate it.
20+
21+
## Revisit trigger
22+
23+
The concrete signal that should reopen this decision.

planning/_templates/design.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
summary: One line — shown in the generated index. Written at creation; finalize at ship to state the realized result.
3+
---
4+
5+
# Design: One-line capitalized title
6+
7+
## Summary
8+
9+
One paragraph. What changes, at the level a reader needs to decide if this
10+
spec is worth reading in full.
11+
12+
## Motivation
13+
14+
Why now. What is broken or missing. Concrete observations / numbers, not
15+
abstract complaints. Link to memory entries or earlier specs when relevant.
16+
17+
## Non-goals
18+
19+
What is deliberately out of scope and (when nontrivial) why. Each item is
20+
a sentence; one line each.
21+
22+
## Design
23+
24+
### 1. <First piece>
25+
26+
What changes, in enough detail that a reader who has not seen the codebase
27+
can follow. Code samples / diagrams welcome.
28+
29+
### 2. <Second piece>
30+
31+
...
32+
33+
## Operations
34+
35+
Out-of-repo steps (DNS, infra, external account changes). Omit if none.
36+
37+
## Out of scope
38+
39+
Already covered above under Non-goals if appropriate. Repeat-list of
40+
explicitly-excluded follow-ups belongs here when the list is long.
41+
42+
## Testing
43+
44+
How we know it landed correctly. New pytest? Smoke check on live URL?
45+
Lint pass? Be specific.
46+
47+
## Risk
48+
49+
What could go wrong, ranked by likelihood × impact. Mitigations.

planning/_templates/plan.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# <slug> — implementation plan
2+
3+
> **For agentic workers:** REQUIRED SUB-SKILL: Use
4+
> superpowers:subagent-driven-development (recommended) or
5+
> superpowers:executing-plans to implement this plan task-by-task. Steps
6+
> use checkbox (`- [ ]`) syntax for tracking.
7+
8+
**Goal:** One sentence — what shipping this plan achieves. No design
9+
rationale; link to the spec for that.
10+
11+
**Spec:** [`design.md`](./design.md)
12+
13+
**Branch:** `feat/my-change` (or `fix/`, `chore/`, etc.)
14+
15+
**Commit strategy:** Per-task commits / single commit / squash on merge.
16+
Whichever fits.
17+
18+
---
19+
20+
### Task 1: <imperative description>
21+
22+
**Files:**
23+
- Modify: `path/to/file.py`
24+
- Create: `path/to/new.py`
25+
26+
One sentence on what this task accomplishes. No deeper reasoning — that's
27+
in the spec.
28+
29+
- [ ] **Step 1: <action>**
30+
31+
Run / edit / verify command. Expected output.
32+
33+
- [ ] **Step 2: <action>**
34+
35+
...
36+
37+
- [ ] **Step 3: Commit**
38+
39+
```bash
40+
git add path/to/file.py
41+
git commit -m "<type>: <subject>"
42+
```
43+
44+
---
45+
46+
### Task 2: ...

planning/_templates/release.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# <project> <version> — <one-line headline>
2+
3+
<One or two sentences: what this release is and its headline change. Say up
4+
front if there are no behavior/API changes.>
5+
6+
<!-- Keep only the sections that apply; reorder/rename freely. A tiny release
7+
may be just the title + one section. Versioning is tag-driven — the
8+
release tag sets the version (`just publish` runs `uv version`), so there
9+
is no pyproject bump. -->
10+
11+
## Feature
12+
13+
- **<name>.** What it adds and how to use it.
14+
15+
## Fix
16+
17+
- **<name>.** What was broken, now fixed (reference the issue/regression).
18+
19+
## Internal refactors
20+
21+
- **<name>.** What changed under the hood, stated as no behavior change.
22+
23+
## Packaging
24+
25+
- Metadata / build / dependency changes visible to installers.
26+
27+
## Why
28+
29+
Context a reader needs for the headline change. Omit for small releases.
30+
31+
## Downstream
32+
33+
What dependents must do — e.g. bump their version floor — or "No action
34+
needed" when there is no API change. Omit if the project has no downstreams.
35+
36+
## Internals
37+
38+
- Coverage / tooling notes.

0 commit comments

Comments
 (0)