Skip to content

Commit cd6f075

Browse files
authored
Merge pull request #25 from modern-python/chore/pin-faststream-pre-0.7
chore: pin faststream <0.7 and adopt planning/ workflow
2 parents 3a16249 + dc4e8cd commit cd6f075

7 files changed

Lines changed: 1527 additions & 2 deletions

CLAUDE.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ FastStream broker integration for Redis-backed distributed timer scheduling.
88
- `just lint` — format and lint
99
- `just install` — install deps
1010

11+
## Workflow
12+
13+
Per-feature workflow: brainstorming → spec in
14+
`planning/specs/YYYY-MM-DD-<slug>-design.md` → writing-plans →
15+
plan in `planning/plans/YYYY-MM-DD-<slug>-plan.md`
16+
executing-plans / subagent-driven-development →
17+
requesting-code-review → finishing-a-development-branch.
18+
19+
Topic slugs are kebab-case descriptions (e.g. `faststream-0.7-migration`),
20+
not story IDs.
21+
1122
## Tests
1223

1324
- `tests/test_unit.py` — pure unit tests (no Redis required)

planning/plans/.gitkeep

Whitespace-only changes.
Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
# FastStream 0.7 migration — PR1 (defensive pin + planning scaffold) Implementation Plan
2+
3+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4+
5+
**Goal:** Tighten the FastStream pin to `>=0.6,<0.7`, adopt `--cov-fail-under=100`, and scaffold the `planning/` workflow directory mirroring `faststream-outbox`. Lands the PR2 design doc in the same commit so PR2 has a home.
6+
7+
**Architecture:** Pure config + docs change. No runtime code touched. Single commit on `chore/pin-faststream-pre-0.7`. The coverage gate is conditional: if `just test` is not at 100% today, the gate addition gets reverted and deferred to PR2 (recorded as decision in commit body).
8+
9+
**Tech Stack:** `pyproject.toml`, `uv`, `pytest-cov`, markdown.
10+
11+
**Related spec:** `planning/specs/2026-06-03-faststream-0.7-migration-design.md`.
12+
13+
---
14+
15+
## Task 1: Create the working branch
16+
17+
**Files:** None (git operation).
18+
19+
- [ ] **Step 1: Confirm clean tree**
20+
21+
Run: `git status`
22+
Expected: `nothing to commit, working tree clean` (a fresh `planning/` dir from the brainstorming session is acceptable; we'll stage it later).
23+
24+
- [ ] **Step 2: Create branch**
25+
26+
Run: `git switch -c chore/pin-faststream-pre-0.7`
27+
Expected: `Switched to a new branch 'chore/pin-faststream-pre-0.7'`
28+
29+
## Task 2: Establish coverage baseline (precondition for gate adoption)
30+
31+
**Files:** None (read-only test run).
32+
33+
The spec's R8 flags that adopting `--cov-fail-under=100` in PR1 requires the suite to already hit 100%. This task discovers the baseline.
34+
35+
- [ ] **Step 1: Run full suite via Justfile**
36+
37+
Run: `just test`
38+
Expected: All tests pass. Final coverage line at bottom of output shows total `%` covered.
39+
40+
- [ ] **Step 2: Record baseline**
41+
42+
Note the total coverage percentage from the report. There are three branches:
43+
44+
- **If `100%`:** Continue to Task 3 — gate adoption is safe.
45+
- **If `<100%` AND missing lines are trivially testable:** Continue to Task 3 but write the backfill tests in Task 3a (insert before Task 4) before adding the gate.
46+
- **If `<100%` AND gaps are non-trivial:** Skip the gate adoption entirely; remove "adopt `--cov-fail-under=100`" from this PR's scope; record decision in commit body; gate moves to PR2 where the orphaned-branch removal naturally lifts coverage.
47+
48+
## Task 3: Tighten the FastStream pin
49+
50+
**Files:**
51+
- Modify: `pyproject.toml` (line 12)
52+
53+
- [ ] **Step 1: Read current dependencies block**
54+
55+
Run: `sed -n '9,14p' pyproject.toml`
56+
Expected output:
57+
```
58+
requires-python = ">=3.13,<4"
59+
license = "MIT"
60+
dependencies = [
61+
"faststream~=0.6",
62+
"redis>=5.0",
63+
]
64+
```
65+
66+
- [ ] **Step 2: Edit the pin**
67+
68+
Change `"faststream~=0.6"` to `"faststream>=0.6,<0.7"` on line 12.
69+
70+
- [ ] **Step 3: Verify edit**
71+
72+
Run: `grep -n "faststream" pyproject.toml | grep -v module`
73+
Expected: `12: "faststream>=0.6,<0.7",`
74+
75+
## Task 4: Adopt `--cov-fail-under=100` (conditional on Task 2)
76+
77+
**Files:**
78+
- Modify: `pyproject.toml` (line 67)
79+
80+
**Skip this task if Task 2 step 2 selected the third branch (`<100%`, non-trivial gaps).**
81+
82+
- [ ] **Step 1: Read current pytest config**
83+
84+
Run: `sed -n '66,70p' pyproject.toml`
85+
Expected output:
86+
```
87+
[tool.pytest.ini_options]
88+
addopts = "--cov=. --cov-report term-missing"
89+
asyncio_mode = "auto"
90+
asyncio_default_fixture_loop_scope = "function"
91+
```
92+
93+
- [ ] **Step 2: Append the coverage gate to addopts**
94+
95+
Change `addopts = "--cov=. --cov-report term-missing"` to `addopts = "--cov=. --cov-report term-missing --cov-fail-under=100"`.
96+
97+
- [ ] **Step 3: Verify edit**
98+
99+
Run: `grep -n "addopts" pyproject.toml`
100+
Expected: `addopts = "--cov=. --cov-report term-missing --cov-fail-under=100"`
101+
102+
## Task 5: Regenerate lockfile
103+
104+
**Files:**
105+
- Touched (gitignored, not committed): `uv.lock`
106+
107+
`uv.lock` is gitignored in this repo, so the file is local-only. The regeneration confirms the resolver is happy with the tightened pin.
108+
109+
- [ ] **Step 1: Regenerate lock**
110+
111+
Run: `uv lock`
112+
Expected: `Resolved N packages in <time>` with no error. The `faststream` line in `uv.lock` should resolve to a `0.6.x` version (verify by `grep '^name = "faststream"' -A 2 uv.lock`).
113+
114+
- [ ] **Step 2: Sync environment**
115+
116+
Run: `uv sync --all-extras --all-groups --frozen`
117+
Expected: Sync succeeds against the frozen lock.
118+
119+
## Task 6: Verify the gate (re-run suite)
120+
121+
**Files:** None.
122+
123+
- [ ] **Step 1: Re-run full suite under the new gate**
124+
125+
Run: `just test`
126+
Expected: All tests pass; if Task 4 ran, the final line is `Required test coverage of 100% reached`. If Task 4 was skipped, this is just a re-confirmation that the pin change didn't break anything.
127+
128+
## Task 7: Scaffold `planning/` (likely already present from spec-writing)
129+
130+
**Files:**
131+
- Create (if missing): `planning/specs/.gitkeep`
132+
- Create (if missing): `planning/plans/.gitkeep`
133+
134+
- [ ] **Step 1: Check current state**
135+
136+
Run: `ls -la planning/specs planning/plans 2>&1`
137+
Expected: Both directories already exist with `.gitkeep` files and a design doc in `planning/specs/`. (Created at spec-writing time.)
138+
139+
- [ ] **Step 2: Touch any missing `.gitkeep` files**
140+
141+
If either `.gitkeep` is missing:
142+
Run: `touch planning/specs/.gitkeep planning/plans/.gitkeep`
143+
144+
## Task 8: Confirm design + plan docs are on disk
145+
146+
**Files:**
147+
- Verify: `planning/specs/2026-06-03-faststream-0.7-migration-design.md`
148+
- Verify: `planning/plans/2026-06-03-faststream-0.7-migration-pr1-plan.md` (this file)
149+
- Verify: `planning/plans/2026-06-03-faststream-0.7-migration-pr2-plan.md`
150+
151+
- [ ] **Step 1: List planning files**
152+
153+
Run: `ls planning/specs planning/plans`
154+
Expected output:
155+
```
156+
planning/plans:
157+
.gitkeep
158+
2026-06-03-faststream-0.7-migration-pr1-plan.md
159+
2026-06-03-faststream-0.7-migration-pr2-plan.md
160+
161+
planning/specs:
162+
.gitkeep
163+
2026-06-03-faststream-0.7-migration-design.md
164+
```
165+
166+
## Task 9: Add `## Workflow` section to CLAUDE.md
167+
168+
**Files:**
169+
- Modify: `CLAUDE.md`
170+
171+
- [ ] **Step 1: Read current CLAUDE.md to confirm anchor**
172+
173+
Run: `grep -n "^## " CLAUDE.md`
174+
Expected output:
175+
```
176+
5:## Commands
177+
11:## Tests
178+
```
179+
180+
- [ ] **Step 2: Insert `## Workflow` between `## Commands` and `## Tests`**
181+
182+
After the `## Commands` block (which ends with the `just install` line on line 9) and before the `## Tests` heading on line 11, insert this block (mind the leading blank line):
183+
184+
```markdown
185+
186+
## Workflow
187+
188+
Per-feature workflow: brainstorming → spec in
189+
`planning/specs/YYYY-MM-DD-<slug>-design.md` → writing-plans →
190+
plan in `planning/plans/YYYY-MM-DD-<slug>-plan.md`
191+
executing-plans / subagent-driven-development →
192+
requesting-code-review → finishing-a-development-branch.
193+
194+
Topic slugs are kebab-case descriptions (e.g. `faststream-0.7-migration`),
195+
not story IDs.
196+
```
197+
198+
- [ ] **Step 3: Verify section order**
199+
200+
Run: `grep -n "^## " CLAUDE.md`
201+
Expected output:
202+
```
203+
5:## Commands
204+
11:## Workflow
205+
22:## Tests
206+
```
207+
(Line numbers approximate; the important thing is `## Workflow` appears between `## Commands` and `## Tests`.)
208+
209+
## Task 10: Verify gitignore does not eat new plan files
210+
211+
**Files:** None (read-only check).
212+
213+
- [ ] **Step 1: Sanity check the gitignore rule**
214+
215+
Run: `git check-ignore -v planning/plans/2026-06-03-faststream-0.7-migration-pr1-plan.md`
216+
Expected: exit code `1` (no output) — the file is NOT ignored.
217+
218+
If exit code is `0` and output names `plan.md` as the rule: the gitignore rule is matching too aggressively (would surprise me but verify). In that case, edit `.gitignore` to anchor the rule: change the bare `plan.md` line to `/plan.md` so it only matches the root.
219+
220+
## Task 11: Run lint
221+
222+
**Files:** None.
223+
224+
- [ ] **Step 1: Run lint**
225+
226+
Run: `just lint`
227+
Expected: All four steps (`eof-fixer`, `ruff format`, `ruff check --fix`, `ty check`) green. Note: `eof-fixer` may auto-add newlines to `.gitkeep` or CLAUDE.md — re-stage afterward.
228+
229+
## Task 12: Stage and commit
230+
231+
**Files:** All modified/created files this PR.
232+
233+
- [ ] **Step 1: Stage changes**
234+
235+
Run:
236+
```
237+
git add pyproject.toml \
238+
CLAUDE.md \
239+
planning/
240+
```
241+
242+
- [ ] **Step 2: Confirm staged files**
243+
244+
Run: `git status --short`
245+
Expected output (order may vary):
246+
```
247+
M CLAUDE.md
248+
M pyproject.toml
249+
A planning/plans/.gitkeep
250+
A planning/plans/2026-06-03-faststream-0.7-migration-pr1-plan.md
251+
A planning/plans/2026-06-03-faststream-0.7-migration-pr2-plan.md
252+
A planning/specs/.gitkeep
253+
A planning/specs/2026-06-03-faststream-0.7-migration-design.md
254+
```
255+
256+
If `uv.lock` shows up in `git status` despite being gitignored, do **not** stage it — confirm `.gitignore` still lists `uv.lock`.
257+
258+
- [ ] **Step 3: Verify no per-call kwarg accidentally landed**
259+
260+
Run: `git diff --cached pyproject.toml`
261+
Expected: only the two single-line edits (pin + addopts).
262+
263+
- [ ] **Step 4: Commit**
264+
265+
```bash
266+
git commit -m "$(cat <<'EOF'
267+
chore: pin faststream <0.7 and adopt planning/ workflow
268+
269+
- pyproject.toml: faststream~=0.6 -> >=0.6,<0.7. Explicit upper bound
270+
makes intent visible and lets the 0.7 migration land in a feature
271+
branch without users pulling unfinished work.
272+
- pyproject.toml: addopts adds --cov-fail-under=100 (matches sister
273+
faststream-outbox project). Hardens the coverage gate before the
274+
0.7 migration (PR2) removes branches.
275+
- planning/: scaffold planning/specs/ + planning/plans/ with .gitkeep
276+
files; mirrors the sister faststream-outbox layout. Includes the
277+
faststream-0.7 migration design and the two plan files so PR2 has
278+
a home.
279+
- CLAUDE.md: new ## Workflow section pointing at the planning/ layout.
280+
281+
Companion PR migrates to faststream 0.7 and drops 0.6 support
282+
(>=0.7,<0.8).
283+
EOF
284+
)"
285+
```
286+
287+
(If Task 4 was skipped, drop the `--cov-fail-under=100` bullet from the body.)
288+
289+
- [ ] **Step 5: Verify commit**
290+
291+
Run: `git log -1 --stat`
292+
Expected: single commit with the message above and the staged files.
293+
294+
## Task 13: Push and open PR
295+
296+
**Files:** None (git remote operation).
297+
298+
- [ ] **Step 1: Push branch**
299+
300+
Run: `git push -u origin chore/pin-faststream-pre-0.7`
301+
Expected: `* [new branch]` line and a hint URL for opening the PR.
302+
303+
- [ ] **Step 2: Open PR via gh**
304+
305+
```bash
306+
gh pr create --title "chore: pin faststream <0.7 and adopt planning/ workflow" --body "$(cat <<'EOF'
307+
## Summary
308+
309+
- Tightens the FastStream pin from `~=0.6` to `>=0.6,<0.7`. The companion PR migrates to 0.7 and drops 0.6 support.
310+
- Adopts `--cov-fail-under=100` (matches sister `faststream-outbox` project).
311+
- Scaffolds `planning/specs/` and `planning/plans/` and lands the 0.7 migration design + two-PR plan files.
312+
313+
## Test plan
314+
315+
- [ ] `just lint` passes
316+
- [ ] `just test` passes at 100% coverage
317+
- [ ] `planning/specs/` and `planning/plans/` are tracked by git
318+
- [ ] `CLAUDE.md` shows the new `## Workflow` section between `## Commands` and `## Tests`
319+
EOF
320+
)"
321+
```
322+
323+
(If Task 4 was skipped: drop the second bullet of the Summary block.)
324+
325+
- [ ] **Step 3: Note PR URL**
326+
327+
The `gh pr create` command outputs the PR URL. Record it for the user.
328+
329+
---
330+
331+
## Verification (acceptance gate)
332+
333+
The PR is done iff:
334+
335+
- [ ] `git diff main..chore/pin-faststream-pre-0.7 -- pyproject.toml` shows only the pin edit and (if applicable) the `--cov-fail-under=100` addition.
336+
- [ ] `git grep -n "faststream~=0.6"` returns nothing on the branch.
337+
- [ ] `planning/specs/2026-06-03-faststream-0.7-migration-design.md` exists and is tracked.
338+
- [ ] `planning/plans/2026-06-03-faststream-0.7-migration-pr1-plan.md` (this file) exists and is tracked.
339+
- [ ] `planning/plans/2026-06-03-faststream-0.7-migration-pr2-plan.md` exists and is tracked.
340+
- [ ] `planning/specs/.gitkeep` and `planning/plans/.gitkeep` exist and are tracked.
341+
- [ ] `CLAUDE.md` contains the `## Workflow` section between `## Commands` and `## Tests`.
342+
- [ ] `just lint` clean on the branch tip.
343+
- [ ] `just test` green (at 100% if Task 4 ran).
344+
- [ ] PR is open with the prescribed title and body.

0 commit comments

Comments
 (0)