From 5aa73263ea1a51df8aa12275533ba46c5d6711b5 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Wed, 10 Jun 2026 23:21:40 +0300 Subject: [PATCH] chore: rework planning conventions; add docs landing/comparison spec + plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codify the spec/plan/architecture boundary in CLAUDE.md, introduce `planning/active/` and `planning/archived/` subdirectories, ship copy-and-fill templates, give every spec and plan YAML frontmatter, and migrate the six already-shipped artifact pairs to the new layout with `status: shipped`, `pr:`, and `outcome:` filled. The first artifacts written under the new convention also land here: - `docs-landing-and-comparison` design + plan (rewrite docs landing, reshape mkdocs nav, add Comparison page) - `planning-conventions` design (this change, dogfooded) Removed `plan.md` from .gitignore — stale catch that would otherwise mask `planning/_templates/plan.md`. Existing plan filenames (`YYYY-MM-DD--plan.md`) are unaffected; the stale catch only ever matched a file literally named `plan.md`. No runtime code, test code, or public API touched. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 1 - CLAUDE.md | 4 +- planning/README.md | 48 ++ planning/_templates/design.md | 55 ++ planning/_templates/plan.md | 56 ++ ...6-10-docs-landing-and-comparison-design.md | 348 +++++++++++ ...-06-10-docs-landing-and-comparison-plan.md | 251 ++++++++ .../2026-06-10-planning-conventions-design.md | 543 ++++++++++++++++++ ...06-03-all-extra-and-planning-dir-design.md | 14 +- ...6-06-03-all-extra-and-planning-dir-plan.md | 8 + ...6-06-03-faststream-0.7-migration-design.md | 14 +- ...026-06-03-faststream-0.7-migration-plan.md | 8 + ...ststream-0.7.1-testbroker-typing-design.md | 14 +- ...faststream-0.7.1-testbroker-typing-plan.md | 8 + .../2026-06-04-foreign-broker-relay-design.md | 14 +- .../2026-06-04-foreign-broker-relay-plan.md | 8 + ...ain-test-flaky-fetch-observation-design.md | 10 + ...drain-test-flaky-fetch-observation-plan.md | 8 + .../2026-06-09-mkdocs-github-pages-design.md | 14 +- .../2026-06-09-mkdocs-github-pages-plan.md | 8 + planning/plans/.gitkeep | 0 planning/specs/.gitkeep | 0 22 files changed, 1412 insertions(+), 22 deletions(-) create mode 100644 planning/README.md create mode 100644 planning/_templates/design.md create mode 100644 planning/_templates/plan.md create mode 100644 planning/active/2026-06-10-docs-landing-and-comparison-design.md create mode 100644 planning/active/2026-06-10-docs-landing-and-comparison-plan.md create mode 100644 planning/active/2026-06-10-planning-conventions-design.md rename planning/{specs => archived}/2026-06-03-all-extra-and-planning-dir-design.md (97%) rename planning/{plans => archived}/2026-06-03-all-extra-and-planning-dir-plan.md (99%) rename planning/{specs => archived}/2026-06-03-faststream-0.7-migration-design.md (98%) rename planning/{plans => archived}/2026-06-03-faststream-0.7-migration-plan.md (99%) rename planning/{specs => archived}/2026-06-04-faststream-0.7.1-testbroker-typing-design.md (98%) rename planning/{plans => archived}/2026-06-04-faststream-0.7.1-testbroker-typing-plan.md (98%) rename planning/{specs => archived}/2026-06-04-foreign-broker-relay-design.md (99%) rename planning/{plans => archived}/2026-06-04-foreign-broker-relay-plan.md (99%) rename planning/{specs => archived}/2026-06-09-drain-test-flaky-fetch-observation-design.md (97%) rename planning/{plans => archived}/2026-06-09-drain-test-flaky-fetch-observation-plan.md (98%) rename planning/{specs => archived}/2026-06-09-mkdocs-github-pages-design.md (98%) rename planning/{plans => archived}/2026-06-09-mkdocs-github-pages-plan.md (99%) delete mode 100644 planning/plans/.gitkeep delete mode 100644 planning/specs/.gitkeep diff --git a/.gitignore b/.gitignore index 13e3f35..b9d607b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,4 @@ dist/ .python-version .venv uv.lock -plan.md /site/ diff --git a/CLAUDE.md b/CLAUDE.md index 730c6fe..502cca0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,7 +17,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Workflow -Per-feature: brainstorming → spec in `planning/specs/YYYY-MM-DD--design.md` → writing-plans → plan in `planning/plans/YYYY-MM-DD--plan.md` → executing-plans / subagent-driven-development → requesting-code-review → finishing-a-development-branch. Slugs are kebab-case descriptions, not story IDs. +Per-feature: brainstorming → spec in `planning/active/YYYY-MM-DD--design.md` → writing-plans → plan in `planning/active/YYYY-MM-DD--plan.md` → executing-plans / subagent-driven-development → requesting-code-review → finishing-a-development-branch. Slugs are kebab-case descriptions, not story IDs. On merge, the pair moves to `planning/archived/` with `status: shipped`, `pr:`, and `outcome:` filled in the frontmatter. See [`planning/README.md`](planning/README.md) for the current index and [`planning/_templates/`](planning/_templates/) for copy-and-fill starting points. + +**Spec** captures the *thinking* — why we are doing this, what the design is, what trade-offs were considered, what is out of scope. Written before code; rarely revised after merge. **Plan** captures the *sequencing* — the ordered checklist of tasks an executor (human or agent) walks. References the spec for the "why"; never re-explains it. **`planning/architecture/`** captures the *invariants* of shipped systems by promoting the relevant parts of a spec after merge. A plan paragraph that would still read correctly with all task numbers and checkboxes removed is design content and belongs in the spec. ## Architecture diff --git a/planning/README.md b/planning/README.md new file mode 100644 index 0000000..7240c46 --- /dev/null +++ b/planning/README.md @@ -0,0 +1,48 @@ +# Planning + +Specs and plans for `faststream-outbox` changes. See +[CLAUDE.md](../CLAUDE.md#workflow) for the per-feature workflow. + +Each change is a paired `*-design.md` + `*-plan.md`. Both halves live +together in `active/` while in flight; both move to `archived/` when the +implementing PR merges. Frontmatter records `status`, `pr`, and +`outcome`. See [`_templates/`](_templates/) for copy-and-fill starting +points. + +## Active + +- **[docs-landing-and-comparison](active/2026-06-10-docs-landing-and-comparison-design.md)** + — Rewrite docs landing, reshape nav into Concepts/Guides/Reference, + add a Comparison page. +- **[planning-conventions](active/2026-06-10-planning-conventions-design.md)** + — This restructure. Codify the spec/plan boundary, add + `active/`/`archived/`/`_templates/`, migrate the existing pairs. + +## Archived (shipped) + +- **[drain-test-flaky-fetch-observation](archived/2026-06-09-drain-test-flaky-fetch-observation-design.md)** + (#48, 2026-06-10) — Drain test waits via the `fetched` recorder + instead of an SQL poll, killing a 3.14 coverage flake. +- **[mkdocs-github-pages](archived/2026-06-09-mkdocs-github-pages-design.md)** + (#45, 2026-06-09) — Docs hosting moves from Read the Docs to GitHub + Pages on `faststream-outbox.modern-python.org`. +- **[foreign-broker-relay](archived/2026-06-04-foreign-broker-relay-design.md)** + (#44, 2026-06-05) — `OutboxSubscriber` officially supports the + FastStream-native decorator relay to Kafka/Rabbit/NATS/Redis with + three guardrails. +- **[faststream-0.7.1-testbroker-typing](archived/2026-06-04-faststream-0.7.1-testbroker-typing-design.md)** + (#43, 2026-06-04) — Adopt FastStream 0.7.1's `TestBroker[Broker, + EnterType]` typing fix; drop two `# ty: ignore` directives. +- **[faststream-0.7-migration](archived/2026-06-03-faststream-0.7-migration-design.md)** + (#42, 2026-06-03) — Migrate to `faststream>=0.7,<0.8`; fix mechanical + break points; drop per-call `middlewares=` kwarg. +- **[all-extra-and-planning-dir](archived/2026-06-03-all-extra-and-planning-dir-design.md)** + (#41, 2026-06-03) — Add `faststream-outbox[all]` aggregate extra; + bootstrap the `planning/` directory itself. + +## Other + +- **[architecture/](architecture/)** — deep-dive reference for shipped + invariants (relay, timers, DLQ, drain, metrics, test broker). +- **[lint-suppressions.md](lint-suppressions.md)** — audit of `noqa` / + `ty: ignore` directives and why each one stays. diff --git a/planning/_templates/design.md b/planning/_templates/design.md new file mode 100644 index 0000000..fb0fe5b --- /dev/null +++ b/planning/_templates/design.md @@ -0,0 +1,55 @@ +--- +status: draft +date: YYYY-MM-DD +slug: my-change +supersedes: null +superseded_by: null +pr: null +outcome: null +--- + +# Design: One-line capitalized title + +## Summary + +One paragraph. What changes, at the level a reader needs to decide if this +spec is worth reading in full. + +## Motivation + +Why now. What is broken or missing. Concrete observations / numbers, not +abstract complaints. Link to memory entries or earlier specs when relevant. + +## Non-goals + +What is deliberately out of scope and (when nontrivial) why. Each item is +a sentence; one line each. + +## Design + +### 1. + +What changes, in enough detail that a reader who has not seen the codebase +can follow. Code samples / diagrams welcome. + +### 2. + +... + +## Operations + +Out-of-repo steps (DNS, infra, external account changes). Omit if none. + +## Out of scope + +Already covered above under Non-goals if appropriate. Repeat-list of +explicitly-excluded follow-ups belongs here when the list is long. + +## Testing + +How we know it landed correctly. New pytest? Smoke check on live URL? +Lint pass? Be specific. + +## Risk + +What could go wrong, ranked by likelihood × impact. Mitigations. diff --git a/planning/_templates/plan.md b/planning/_templates/plan.md new file mode 100644 index 0000000..c8106a4 --- /dev/null +++ b/planning/_templates/plan.md @@ -0,0 +1,56 @@ +--- +status: draft +date: YYYY-MM-DD +slug: my-change +spec: my-change +pr: null +--- + +# — implementation plan + +> **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. + +**Goal:** One sentence — what shipping this plan achieves. No design +rationale; link to the spec for that. + +**Spec:** [`planning/active/YYYY-MM-DD-my-change-design.md`](./YYYY-MM-DD-my-change-design.md) + +**Branch:** `feat/my-change` (or `fix/`, `chore/`, etc.) + +**Commit strategy:** Per-task commits / single commit / squash on merge. +Whichever fits. + +--- + +### Task 1: + +**Files:** +- Modify: `path/to/file.py` +- Create: `path/to/new.py` + +One sentence on what this task accomplishes. No deeper reasoning — that's +in the spec. + +- [ ] **Step 1: ** + + Run / edit / verify command. Expected output. + +- [ ] **Step 2: ** + + ... + +- [ ] **Step 3: Commit** + + ```bash + git add path/to/file.py + git commit -m ": + + Co-Authored-By: Claude Opus 4.7 (1M context) " + ``` + +--- + +### Task 2: ... diff --git a/planning/active/2026-06-10-docs-landing-and-comparison-design.md b/planning/active/2026-06-10-docs-landing-and-comparison-design.md new file mode 100644 index 0000000..1fb4d6d --- /dev/null +++ b/planning/active/2026-06-10-docs-landing-and-comparison-design.md @@ -0,0 +1,348 @@ +--- +status: draft +date: 2026-06-10 +slug: docs-landing-and-comparison +supersedes: null +superseded_by: null +pr: null +outcome: null +--- + +# Design: Rework the docs landing + nav, add a comparison page + +## Summary + +The current docs are reference-grade but new-user-hostile: `docs/index.md` +is a 22-line TOC, the mkdocs nav opens with "Relay to a foreign broker" +(advanced use case), the canonical "FastAPI + outbox" guide is buried at +position 7, and there is no answer to the first question a prospective +user asks: *"is this the right tool for me?"*. + +This change does three things, in one pass: + +1. Rewrite `docs/index.md` as a real landing page — value proposition, + decision tree, "you're here because" jumplist into the rest of the + docs. +2. Re-shape `mkdocs.yml` nav into four progressive-disclosure sections + (Getting started → Concepts → Guides → Reference) without moving or + renaming any existing files, so all URLs and external links stay + stable. +3. Add a new `docs/concepts/comparison.md` page that names alternatives + (raw outbox, CDC / Debezium, Kafka transactions, PG-NOTIFY, + Celery, FastStream-only) and says when each is the better choice. + +No runtime code, test code, or public API is touched. No mkdocs plugins +are added. + +## Motivation + +- **The landing page tells a new user nothing.** `docs/index.md` is a + bullet list of page titles. A reader arriving from PyPI, the README, + or search has no signal whether this library fits their problem; they + must guess and click. Every other modern Python lib's docs index + opens with a value-prop + decision-tree pattern (Pydantic, SQLAlchemy + 2.0, FastAPI, FastStream itself). Matching that pattern is the + single highest-ROI docs move available. +- **The nav order is inverse to user intent.** Today's order: + + ``` + Relay → Basic → Subscriber → DLQ → Publisher → Router + → FastAPI → Timers → Testing → Schema → Observability + ``` + + Most adopters land here for "transactional outbox under FastAPI" + (the canonical use case explicitly named in `usage/fastapi.md`), + not for "relay outbox rows to Kafka". Putting Relay first reads as + a topic-hierarchy mistake to anyone scanning the sidebar. The + Basic-usage page (the actual getting-started flow) is the second + Usage entry but lives alongside Reference material. + +- **No comparison page = unanswerable "should I use this?".** The + README does some of this work, but docs readers don't always arrive + via the README. The team has already done the CDC / WAL analysis + (memory: `cdc_wal_rejected.md`, 2026-05-07) — that thinking deserves + a public home so users and contributors don't ask again. + +- **Cheap to land.** This is config + two pages; nothing depends on + it, and follow-ups (production checklist, troubleshooting, diagrams, + DRY pass on the transactional-contract paragraph that appears in 6 + pages) layer cleanly on top. + +## Non-goals (this spec) + +Deliberately *not* covered here; each is a candidate follow-on spec: + +- **B — Operator pages.** Production checklist, Troubleshooting, + Alembic migration snippet. Pulls scattered operator content into + one section. Highest-value follow-on. +- **C — Diagrams + worked examples.** Mermaid sequence diagrams for + publish path / fetch CTE / lease lifecycle / drain phases; an + end-to-end "checkout" worked example wiring publisher + subscriber + + DLQ + relay. +- **D — DRY the canon.** Pull the transactional-contract paragraph + (currently repeated near-verbatim in `index.md`, `how-it-works.md`, + `basic.md`, `publisher.md`, `fastapi.md`, `relay.md`) into a single + canonical source and replace duplicates with one-line links. Stops + the docs drifting against each other. +- **F — Diátaxis rewrite.** Full restructure as Tutorial / How-to / + Reference / Explanation. Larger commitment than this pass; the + four-section nav this spec lands gestures at the same shape without + committing to it. + +Also out of scope: + +- **File renames / moves.** Every existing page keeps its current path. + The README, the recently-migrated GH Pages site, and any external + inbound links all keep working. The nav reshape is metadata-only. +- **mkdocs plugins / theme changes.** No `mike` for versioning, no + social cards, no privacy plugin. The current minimal theme is + intentional; expansion is a separate conversation. +- **Voice / tone edits to existing pages.** The reference voice is + already strong; this spec touches the landing and adds one new + page only. +- **Removing the duplicated transactional-contract paragraphs.** That + is the D follow-on. Leaving it untouched here keeps the diff small + and the risk profile near zero. + +## Design + +### 1. Rewrite `docs/index.md` + +The new landing has four blocks, in order: + +**Block A — Value prop (one paragraph).** Same content as today's first +paragraph, lightly tightened. States what the library is and the +transactional-outbox contract in one sentence. + +**Block B — "Use it when / don't use it when" (two short lists).** +Concrete and binary — no hedging. Examples: + +> **Use `faststream-outbox` when** +> +> - You already have Postgres and don't want to add a message bus just +> to get at-least-once delivery alongside your domain writes. +> - You want the row insert to commit atomically with the rest of your +> SQLAlchemy transaction (no two-phase commit, no Sagas). +> - You're building on FastStream or FastAPI and want the same +> subscriber / dependency-injection ergonomics for an outbox. +> +> **Reach for something else when** +> +> - You're already running Kafka / Rabbit / NATS *and* don't need +> transactional atomicity with a DB write → use that broker directly. +> - You need sub-second scheduled-delivery precision → see +> [Timers § latency floor](usage/timers.md#latency-floor). +> - You're on a non-Postgres database → this package is Postgres-only +> at v0. CDC / Debezium may be a better fit (see +> [Comparison](concepts/comparison.md)). + +**Block C — Decision tree → next page.** A small table that takes a +user's intent and routes them into the right starting page: + +> | If you want to… | Start at | +> |---|---| +> | See it work end-to-end on a FastAPI app | [FastAPI integration](usage/fastapi.md) | +> | Relay outbox rows to Kafka / RabbitMQ / NATS / Redis | [Relay to Kafka / RabbitMQ / NATS](usage/relay.md) | +> | Understand the architecture before adopting | [How it works](introduction/how-it-works.md) | +> | Compare against CDC / Kafka transactions / a hand-rolled outbox | [Comparison](concepts/comparison.md) | +> | Install and write the first publisher / subscriber | [Installation](introduction/installation.md) → [Basic usage](usage/basic.md) | + +**Block D — Documentation map.** The structured index that today's +landing already is, but organized into the four sections the new nav +uses (Getting started / Concepts / Guides / Reference). Bullet list, +one line per page, terse description after the link. Replaces the flat +list of 11 page titles. + +### 2. Reshape `mkdocs.yml` nav + +Replace the current two-section nav (Introduction / Usage) with four +sections. **No file paths change.** This is purely a `nav:` block +rewrite: + +```yaml +nav: + - Overview: index.md + - Getting started: + - Installation: introduction/installation.md + - Basic usage: usage/basic.md + - Concepts: + - How it works: introduction/how-it-works.md + - Comparison: concepts/comparison.md # new — see §3 + - Guides: + - FastAPI integration: usage/fastapi.md + - Relay to Kafka / RabbitMQ / NATS: usage/relay.md + - Timers: usage/timers.md + - Testing: usage/testing.md + - Schema validation: usage/schema-validation.md + - Reference: + - Subscriber: usage/subscriber.md + - Publisher: usage/publisher.md + - Router: usage/router.md + - Dead-letter queue: usage/dlq.md + - Observability: usage/observability.md +``` + +Load-bearing choices: + +- **"FastAPI integration" leads the Guides section.** It's the canonical + use case the architecture is designed around; surfacing it first + matches the README and the structure of `usage/fastapi.md` itself + ("the outbox + FastAPI is the canonical use case"). +- **"Relay to Kafka / RabbitMQ / NATS" replaces "Relay to a foreign + broker"** as a nav label only — the file stays at `usage/relay.md`. + Reasons: (a) the names of the supported brokers are what users + search for; (b) "a foreign broker" is jargon that means nothing + before clicking through. The H1 inside `relay.md` stays + "Relay to a foreign broker" to avoid pointlessly churning page + titles and inbound links to anchored sections. +- **Basic usage moves from Usage to Getting started**, sitting next to + Installation. The page is a getting-started narrative ("1. Declare + the outbox table → 2. Create the broker → 3. Register a subscriber + → 4. Publish a message"), so placing it under Getting started + matches its actual content. +- **Subscriber / Publisher / Router / DLQ / Observability move to + Reference.** They're reference pages today — exhaustive option + tables, label-set tables, schema columns. The label change matches + what they actually are. +- **`how-it-works.md` stays under `introduction/`** on disk but moves + to Concepts in the nav. The file path stays so external links + (notably the README's "How it works" link, and the README's recent + GH-Pages URL update per the `mkdocs-github-pages` spec) keep + resolving. Concepts is the user-facing label. +- **`navigation.expand` already on in `mkdocs.yml`.** The four-section + expansion stays usable in the sidebar without scrolling — Reference + is five entries, Guides is five, Concepts is two, Getting started + is two. Material theme's sidebar handles this size cleanly. + +### 3. New file `docs/concepts/comparison.md` + +New top-level file under a new `concepts/` directory. Sections: + +1. **`faststream-outbox` vs writing your own.** Honest about the + complete list of pieces you'd re-implement: lease tokens, partial + index design, fetch-and-claim CTE shape, retry-strategy template, + lease-loss invariant on terminal writes, `validate_schema()`, + drain semantics, LISTEN/NOTIFY short-circuit, NOTIFY suppression + on future-dated rows, `timer_id` dedup, DLQ atomicity CTE. Cross- + linked into the relevant existing reference pages so the user can + verify scope rather than take the list on faith. +2. **vs CDC (Debezium, logical replication).** Direct port of the + reasoning from memory `cdc_wal_rejected.md`. CDC wins when you + already need WAL-level change capture for analytics, when you want + transparent capture of writes from non-FastStream services, or + when you cannot tolerate the polling overhead. `faststream-outbox` + wins when you control the producer code, when the async-Python + tooling for logical replication is too thin (the memory's load- + bearing reason), and when handler-level retry / DLQ / scheduling + semantics are needed inline. +3. **vs Kafka transactions (or Rabbit publisher confirms).** Atomic + `DB-write + bus-publish` is achievable with Kafka transactions + plus 2PC or with idempotent producers + an inbox pattern. Trade- + offs: requires Kafka (operational footprint, schema registry, + consumer-group rebalancing), no native cancellation / timers / + `timer_id` dedup, no single-tx contract with arbitrary domain + writes. +4. **vs plain PG-NOTIFY.** PG-NOTIFY is fire-and-forget and lossy + across listener disconnect; `faststream-outbox` keeps the row + durable until the handler ack and uses NOTIFY only as a wake-up + short-circuit on top of polling. Worked example: what happens to + a NOTIFY when the listener was reconnecting at emit time, in each + shape. +5. **vs Celery + DB result backend.** Different abstraction level — + Celery is task queues, `faststream-outbox` is message routing + with FastStream subscriber semantics. Use Celery when you want + ad-hoc background jobs initiated from anywhere; use this when you + want at-least-once dispatch of *events* tied to DB transactions + and prefer FastStream's broker/subscriber model. +6. **vs FastStream + KafkaBroker / RabbitBroker directly.** Use the + foreign broker directly when you don't need transactional + atomicity with a DB write; use `faststream-outbox` plus + [Relay](../usage/relay.md) when the producer side does need it. + This is not an either/or — the canonical relay shape composes + both. + +Each section ends with a one-line "TL;DR" verdict so a scanning reader +can lift the answer without reading the discussion. + +The page lives at `docs/concepts/comparison.md` (creates a new +`concepts/` directory under `docs/`). That keeps it discoverable on +disk under a category name that matches the nav section label, and +leaves room for future Concepts pages (e.g. the D follow-on could +land a "Transactional contract" canonical page here). + +### 4. Cross-links from existing pages into `comparison.md` + +Minimal, no other content changes: + +- `introduction/how-it-works.md` § "The transactional outbox pattern": + add a one-line "See [Comparison](../concepts/comparison.md) for when + CDC or Kafka transactions are the better fit." +- `usage/relay.md` § intro paragraph: add a tail "If you don't have a + database write to atomically commit alongside, use the foreign + broker directly — see [Comparison](../concepts/comparison.md)." + +Just two links. The comparison page is also reachable from the new +landing's decision-tree table, so deep cross-linking from every page +isn't load-bearing. + +## Operations + +None — this is config + new docs content, fully in-repo. The +`mkdocs-github-pages` deploy workflow (`.github/workflows/docs.yml`, +landed 2026-06-09) re-deploys on push to `main` whenever `docs/**` or +`mkdocs.yml` changes, which both halves of this spec trigger. + +After landing: + +- The `concepts/comparison.md` URL becomes available at + `https://faststream-outbox.modern-python.org/concepts/comparison/`. +- All existing URLs (`usage/relay/`, `usage/fastapi/`, etc.) continue + to resolve. The README links untouched by this spec keep working; + the README links updated in `mkdocs-github-pages` keep working. + +## Testing + +This spec is content + nav config; correctness is observable on the +live site: + +- `mkdocs build --strict` succeeds locally and in the deploy workflow + (catches broken cross-links from `index.md` → new sections, + catches a misspelled file path in the nav). +- The deploy workflow run on merge completes green and the new + Comparison page renders at its URL. +- The reshaped sidebar renders with four sections, expanded by + default (`navigation.expand` is already on), no entries missing. +- Spot-check that every page from the previous nav still appears in + the new nav — this spec promises no pages are dropped, only + re-grouped. + +No new pytest hooks are added. `just lint-ci` continues to lint the +files that change (markdown formatting via the ruff EOF fixer, yaml +formatting on `mkdocs.yml`). + +## Risk + +- **Nav reshuffle confuses bookmarks of the *sidebar position*.** Low + risk: deep links (the URLs people actually bookmark) don't change. + Anyone navigating by "the page two below DLQ in the sidebar" is + exotic enough to absorb the change. Material theme search and the + decision-tree table on the new landing both let users re-find pages + by intent rather than by old position. +- **Comparison page is opinionated and could age poorly.** Mitigated + by sourcing claims from the existing architecture / memory and + marking the CDC section as reflecting a 2026-05-07 reassessment. + Easy to update later when the async-Python logical-replication + tooling situation changes. +- **External SEO for "Relay to a foreign broker"** — the nav label + change reshapes how the page appears in search results from + mkdocs-material's social cards (if ever enabled) and breadcrumbs. + The H1 stays "Relay to a foreign broker", so canonical SEO is + unchanged; only the sidebar label and breadcrumb text shift. Net + expected to be neutral-to-positive (more specific terms in the + visible label). +- **The four-section nav grows.** Adding Concepts and Guides as + distinct sections invites future content to be slotted in. If + follow-on specs B/C/D land, Operations could become a fifth + section (Production checklist, Troubleshooting). The nav scales + fine to five sections under Material theme; the structure + established here is the seed. diff --git a/planning/active/2026-06-10-docs-landing-and-comparison-plan.md b/planning/active/2026-06-10-docs-landing-and-comparison-plan.md new file mode 100644 index 0000000..ac9708c --- /dev/null +++ b/planning/active/2026-06-10-docs-landing-and-comparison-plan.md @@ -0,0 +1,251 @@ +--- +status: draft +date: 2026-06-10 +slug: docs-landing-and-comparison +spec: docs-landing-and-comparison +pr: null +--- + +# docs-landing-and-comparison — implementation plan + +> **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. + +**Goal:** Rewrite `docs/index.md` as a real landing page, reshape +`mkdocs.yml` nav into Getting-started / Concepts / Guides / Reference, and +add a new Comparison page under a new `docs/concepts/` directory. + +**Spec:** [`planning/active/2026-06-10-docs-landing-and-comparison-design.md`](./2026-06-10-docs-landing-and-comparison-design.md) + +**Branch:** `docs/landing-and-comparison` + +**Commit strategy:** Per-task commits. Task 4 is verification-only and +produces no commit. + +--- + +### Task 1: Branch + create the Comparison page + cross-link callouts + +**Files:** +- Create: `docs/concepts/comparison.md` +- Modify: `docs/introduction/how-it-works.md` +- Modify: `docs/usage/relay.md` + +Creates the new page that the rewritten landing (Task 3) and the +cross-link callouts will both reference. Doing the callouts in the same +commit keeps "the link target lands together with its links." + +- [ ] **Step 1: Create the feature branch from `main`** + + Run: `git switch -c docs/landing-and-comparison` + Expected: `Switched to a new branch 'docs/landing-and-comparison'`. + +- [ ] **Step 2: Create `docs/concepts/comparison.md`** + + Create the directory `docs/concepts/` and inside it write + `comparison.md` with the six sections defined in [spec §3 + ](./2026-06-10-docs-landing-and-comparison-design.md#3-new-file-docsconceptscomparisonmd): + + 1. `faststream-outbox` vs writing your own + 2. vs CDC (Debezium, logical replication) + 3. vs Kafka transactions (or Rabbit publisher confirms) + 4. vs plain PG-NOTIFY + 5. vs Celery + DB result backend + 6. vs FastStream + `KafkaBroker` / `RabbitBroker` directly + + Each section ends with a one-line **TL;DR** verdict. Section 2 sources + its CDC analysis from the existing memory entry + `cdc_wal_rejected.md` (2026-05-07); reflect that the reassessment was + done on that date. + + Cross-link inline into existing reference pages where natural — + e.g. the "vs writing your own" section can name the + `subscriber`/`publisher`/`dlq` pages whose mechanisms the user would + re-implement. + +- [ ] **Step 3: Add a one-line callout in `docs/introduction/how-it-works.md`** + + In the `## The transactional outbox pattern` section, add at the end + of the final paragraph: + + > See [Comparison](../concepts/comparison.md) for when CDC or Kafka + > transactions are the better fit. + +- [ ] **Step 4: Add a one-line callout in `docs/usage/relay.md`** + + At the end of the intro paragraph (before the first `## Why an outbox + relay`), add: + + > If you don't have a database write to atomically commit alongside, + > use the foreign broker directly — see + > [Comparison](../concepts/comparison.md). + +- [ ] **Step 5: Smoke-build the docs locally** + + Run: `uvx --with-requirements docs/requirements.txt mkdocs build --strict` + Expected: build completes, no warnings. The new page does not yet + appear in the sidebar (Task 2 wires it in), but `--strict` will catch + any broken cross-link from the two callouts. + +- [ ] **Step 6: Commit** + + ```bash + git add docs/concepts/comparison.md docs/introduction/how-it-works.md docs/usage/relay.md + git commit -m "docs: add comparison page and cross-link callouts + + Co-Authored-By: Claude Opus 4.7 (1M context) " + ``` + +--- + +### Task 2: Reshape `mkdocs.yml` nav + +**Files:** +- Modify: `mkdocs.yml` + +Replace the two-section nav (`Introduction` / `Usage`) with the +four-section structure in [spec §2 +](./2026-06-10-docs-landing-and-comparison-design.md#2-reshape-mkdocsyml-nav). +No file paths change; only the `nav:` block. + +- [ ] **Step 1: Edit `mkdocs.yml`** + + Replace the existing `nav:` block (currently `Overview` + `Introduction` + + `Usage`) with: + + ```yaml + nav: + - Overview: index.md + - Getting started: + - Installation: introduction/installation.md + - Basic usage: usage/basic.md + - Concepts: + - How it works: introduction/how-it-works.md + - Comparison: concepts/comparison.md + - Guides: + - FastAPI integration: usage/fastapi.md + - Relay to Kafka / RabbitMQ / NATS: usage/relay.md + - Timers: usage/timers.md + - Testing: usage/testing.md + - Schema validation: usage/schema-validation.md + - Reference: + - Subscriber: usage/subscriber.md + - Publisher: usage/publisher.md + - Router: usage/router.md + - Dead-letter queue: usage/dlq.md + - Observability: usage/observability.md + ``` + + Load-bearing details (per spec): "Relay to Kafka / RabbitMQ / NATS" is + the nav *label* only — the file stays at `usage/relay.md` and its H1 + is unchanged. Don't touch `mkdocs.yml` outside the `nav:` block. + +- [ ] **Step 2: Smoke-build and visually scan** + + Run: `uvx --with-requirements docs/requirements.txt mkdocs build --strict` + Expected: build clean. Open `site/index.html` (or run `mkdocs serve` + briefly) and confirm the sidebar shows four sections in the expected + order, all eleven existing pages plus the new Comparison page are + present, none dropped. + +- [ ] **Step 3: Commit** + + ```bash + git add mkdocs.yml + git commit -m "docs: reshape nav into Getting started / Concepts / Guides / Reference + + Co-Authored-By: Claude Opus 4.7 (1M context) " + ``` + +--- + +### Task 3: Rewrite `docs/index.md` as a landing page + +**Files:** +- Modify: `docs/index.md` + +Replace today's 22-line TOC with the four-block landing per [spec §1 +](./2026-06-10-docs-landing-and-comparison-design.md#1-rewrite-docsindexmd). +The new page is the front door — every other doc is reachable from one +of the four blocks. + +- [ ] **Step 1: Replace `docs/index.md` contents** + + Structure: + + - **Block A** — value-prop paragraph (lightly tightened version of + today's first paragraph). + - **Block B** — "Use it when / Reach for something else when" two + short bulleted lists. Concrete, binary, no hedging. See spec §1 + Block B for example wording. + - **Block C** — decision-tree table mapping user intent → starting + page. See spec §1 Block C for the table. + - **Block D** — documentation map grouped by the four nav sections + (Getting started / Concepts / Guides / Reference). One line per + page, terse description after the link. + + All internal links use the relative path from `docs/index.md`: + `introduction/installation.md`, `concepts/comparison.md`, + `usage/fastapi.md`, etc. + +- [ ] **Step 2: Smoke-build** + + Run: `uvx --with-requirements docs/requirements.txt mkdocs build --strict` + Expected: clean. Block C and Block D each contain ~5–10 internal + links; `--strict` catches any broken target. + +- [ ] **Step 3: Commit** + + ```bash + git add docs/index.md + git commit -m "docs: rewrite landing page with value prop, decision tree, doc map + + Co-Authored-By: Claude Opus 4.7 (1M context) " + ``` + +--- + +### Task 4: Verify + +**Files:** none modified; no commit produced. + +Final pass before opening the PR. + +- [ ] **Step 1: Full strict build** + + Run: `uvx --with-requirements docs/requirements.txt mkdocs build --strict` + Expected: clean. + +- [ ] **Step 2: Lint pass** + + Run: `just lint` + Expected: `eof-fixer`, `ruff format`, `ruff check`, `ty check` all + pass. Markdown EOF + YAML formatting on `mkdocs.yml` are the only + things touched in this PR. + +- [ ] **Step 3: Manual sidebar scan** + + Run: `uvx --with-requirements docs/requirements.txt mkdocs serve` + Open the served site and confirm: + + - Sidebar shows four sections in order: Getting started, Concepts, + Guides, Reference. + - Every page from the pre-change nav is still reachable. + - The new Comparison page appears under Concepts and renders cleanly. + - The decision-tree table on the landing page routes correctly into + `usage/fastapi.md`, `usage/relay.md`, `introduction/how-it-works.md`, + `concepts/comparison.md`, `introduction/installation.md`, and + `usage/basic.md`. + - The "Relay to a foreign broker" H1 inside `usage/relay.md` is + unchanged (spec invariant — only the nav label changed). + +- [ ] **Step 4: Open the PR** + + Stop. Hand off to `superpowers:requesting-code-review` / + `superpowers:finishing-a-development-branch` per the standard + workflow. The convention in [`planning/README.md`](../README.md): + on merge, both this plan and its paired spec move to + `planning/archived/` and get `status: shipped`, `pr:`, and + `outcome:` filled. diff --git a/planning/active/2026-06-10-planning-conventions-design.md b/planning/active/2026-06-10-planning-conventions-design.md new file mode 100644 index 0000000..769e048 --- /dev/null +++ b/planning/active/2026-06-10-planning-conventions-design.md @@ -0,0 +1,543 @@ +--- +status: draft +date: 2026-06-10 +slug: planning-conventions +supersedes: null +superseded_by: null +pr: null +outcome: null +--- + +# Design: Rework planning conventions + migrate existing artifacts + +## Summary + +Codify the spec / plan boundary, add `active/` and `archived/` subdirectories +under `planning/`, ship copy-and-fill templates, give every spec and plan +YAML frontmatter, and migrate the six already-shipped artifact pairs to the +new layout — all in one PR. + +The goal is **higher orientation per glance** (which work is in flight, which +shipped, what each was about, what shipped under it) and a **clear contract +for what goes in a spec vs. what goes in a plan** so plans stop absorbing +design content and growing without bound. + +No runtime code, no test code, no public API touched. + +## Motivation + +Concrete observations from the current `planning/` tree: + +- **The spec / plan boundary is undefined.** `CLAUDE.md` names both files + and the workflow that produces them but does not say what content each + owns. Result: plans absorb design rationale that belongs in the spec. + Example from `2026-06-04-foreign-broker-relay-plan.md` (Task 1, Step 2): + > "We add it to the `dev` dependency group (not + > `[project.optional-dependencies]`, which is for runtime extras) so + > that user installs of `faststream-outbox` do not pick up Kafka + > transport unless they explicitly depend on it." + + That is a design trade-off, not an executor instruction. It belongs in + the spec. Six paired artifacts all leak similar content in similar + ways; the largest plan is 62 KB. + +- **Active vs. shipped is invisible from `ls`.** Every spec and plan piles + into a single flat directory each, sorted by date. Six pairs today; 50 + pairs in a year. Finding "what's in flight" requires opening files to + read the `Status:` line in the body. The reader pays the cost on every + visit; the writer (whoever ships the change) almost never updates the + status line — every existing spec still says `Status: Draft` or + `Status: Approved` even though the work merged weeks ago. + +- **No index.** There is no `planning/README.md` summarizing what each + artifact is about. The slug carries some signal + (`mkdocs-github-pages`, `foreign-broker-relay`) but slug alone is + thin — a one-line summary per artifact pays back on every visit and + costs the author one line. + +- **Style is mimetic.** New specs are written by reading the most recent + spec and matching shape. This has worked (the six existing specs are + consistent), but it is fragile — one contributor in a hurry copies a + pre-2026-06 file that did not yet have the convention's current shape + and the drift begins. A template file makes the convention explicit and + copy-pasteable. + +- **No PR / merge linkage.** When a spec ships, there is no record of + *which* PR shipped it. Tracing a decision back from code requires + guessing the slug, opening the spec, then reading git history for + files mentioned in the spec to find the merge. A one-line + `outcome:` frontmatter entry (`PR #47, merged 2026-06-09`) collapses + that to a single field on the artifact. + +- **No "this overturns that".** The CDC/WAL rejection memo lives only in + `/Users/kevinsmith/.claude/projects/.../memory/cdc_wal_rejected.md`, + not in `planning/`. If a future spec changes a decision recorded in + an earlier spec, there is nothing in the file system that flags the + relationship — readers of the older spec take its conclusion at face + value. A `supersedes:` / `superseded_by:` link makes the relationship + visible. + +The fix for all of this is small, single PR, low risk: a directory split, +a template, a frontmatter convention, an index, and a migration of the +six existing pairs. + +## Non-goals + +Deliberately *not* covered here; each is a candidate follow-on: + +- **`just plans` index generator.** The frontmatter conventions this spec + lands make a generator a 30-line script, but the index is small enough + (six artifacts grown to maybe twenty over the next year) that a hand- + maintained `planning/README.md` is sufficient. Automate later if the + list grows. + +- **Trimming existing plans down to fit the new spec / plan boundary.** + Existing plans stay verbatim in `archived/`. Promoting design content + from a shipped plan back into its paired spec is an opportunistic + follow-on — touching frozen history without a forcing function is + rarely worth it. The convention shapes *future* plans; existing ones + are historical artifacts. + +- **Relocating `planning/architecture/`.** It does not belong in + `planning/` (it documents shipped invariants, not pending work), but + moving it changes URLs and inbound links from `CLAUDE.md`. Separate + spec. + +- **Workflow tooling.** No new CI checks (e.g. "frontmatter must parse"). + Editor support for frontmatter is universal; the cost of a malformed + block surfaces immediately on PR review. + +- **A "tiny-change" lane that bypasses the spec → plan flow.** Worth + defining (typo fix, dep bump, etc.) but orthogonal to the conventions + this spec lands. Separate change to `CLAUDE.md`. + +## Design + +### 1. The spec / plan boundary, codified + +Three sentences added to `CLAUDE.md`'s Workflow section, alongside the +existing per-feature pipeline: + +> **Spec** captures the *thinking* — why we are doing this, what the +> design is, what trade-offs were considered, what is out of scope. +> Written before code; rarely revised after merge. +> +> **Plan** captures the *sequencing* — the ordered checklist of tasks +> an executor (human or agent) walks. References the spec for the +> "why"; never re-explains it. Often a markdown checkbox list with a +> few prose notes between groups. +> +> **`planning/architecture/`** captures the *invariants* of shipped +> systems — the load-bearing properties future contributors must +> preserve. Written after merge by promoting the relevant parts of a +> spec. + +A plan that ends up explaining *why* a design choice was made (versus +*what step to take next*) should move that explanation back into the +spec. The smell to watch for: any plan paragraph that would still read +correctly if you removed all the task numbers and checkboxes — that is +design content. + +### 2. Directory layout + +``` +planning/ +├── README.md # NEW — index, hand-maintained +├── _templates/ +│ ├── design.md # NEW — copy-and-fill spec +│ └── plan.md # NEW — copy-and-fill plan +├── active/ # NEW — in-flight pairs +│ ├── 2026-06-10-docs-landing-and-comparison-design.md +│ ├── 2026-06-10-planning-conventions-design.md # ← this spec +│ └── (plans land here as they get written) +├── archived/ # NEW — shipped pairs, frozen +│ ├── 2026-06-03-all-extra-and-planning-dir-design.md +│ ├── 2026-06-03-all-extra-and-planning-dir-plan.md +│ ├── 2026-06-03-faststream-0.7-migration-design.md +│ ├── 2026-06-03-faststream-0.7-migration-plan.md +│ ├── 2026-06-04-faststream-0.7.1-testbroker-typing-design.md +│ ├── 2026-06-04-faststream-0.7.1-testbroker-typing-plan.md +│ ├── 2026-06-04-foreign-broker-relay-design.md +│ ├── 2026-06-04-foreign-broker-relay-plan.md +│ ├── 2026-06-09-drain-test-flaky-fetch-observation-design.md +│ ├── 2026-06-09-drain-test-flaky-fetch-observation-plan.md +│ ├── 2026-06-09-mkdocs-github-pages-design.md +│ └── 2026-06-09-mkdocs-github-pages-plan.md +├── architecture/ # unchanged (separate spec) +└── lint-suppressions.md # unchanged +``` + +The old `specs/` and `plans/` directories disappear. Pairing is now +implicit in the shared `YYYY-MM-DD--` prefix and explicit in +frontmatter. Both halves of a pair always live in the same directory +(`active/` or `archived/`); a pair cannot be half-shipped because the +plan is the executor's record of execution. + +### 3. Lifecycle + +``` + ┌─────────────────────────┐ + spec drafted ───▶│ planning/active/ │ + │ status: draft │ + └────────────┬────────────┘ + │ + spec approved + ▼ + ┌─────────────────────────┐ + │ planning/active/ │ + │ status: approved │ + │ plan written │ + └────────────┬────────────┘ + │ + PR merged + ▼ + ┌─────────────────────────┐ + │ planning/archived/ │ + │ status: shipped │ + │ pr: 51 │ + │ outcome: "merged …" │ + └─────────────────────────┘ +``` + +The move from `active/` to `archived/` happens in the same PR that +merges the implementation (or an immediate follow-up). Until merge, +the artifact is `active/`; the moment the code lands, the spec + plan +move to `archived/` with `status: shipped`, `pr:`, and `outcome:` +filled. + +`planning/README.md` is updated in the same PR — one line moves from +the "Active" section to the "Archived" section. Hand-maintained; +small cost per merge; payoff on every visit thereafter. + +### 4. Frontmatter + +YAML frontmatter on every spec and every plan: + +**Spec:** +```yaml +--- +status: draft | approved | shipped | superseded +date: 2026-06-10 +slug: planning-conventions +supersedes: null # or of older spec +superseded_by: null # or of newer spec +pr: null # or "47", set when merged +outcome: null # or "merged 2026-06-09 as #47" +--- +``` + +**Plan:** +```yaml +--- +status: draft | approved | shipped +date: 2026-06-10 +slug: planning-conventions +spec: planning-conventions # paired spec slug, sanity check +pr: null +--- +``` + +Notes: + +- **YAML, not body header.** The current `**Status:** Draft / **Date:** + ... / **Slug:** ...` body header is human-readable but not machine- + readable without a custom parser. Frontmatter is parseable by every + static-site generator, every editor, and a one-liner shell script if + we ever automate the index. Migration cost is small (six pairs, twelve + files, ~10 lines each). +- **`status: superseded`** is a separate top-level state, not a sub- + state of `shipped`. A spec that was approved, partly implemented, then + overturned by a later spec is `superseded` even if no PR shipped it. +- **`pr:` is a string**, not a number — supports cross-repo references + later if ever needed, and keeps YAML simple. +- **`outcome:` is freeform** — typically `"merged 2026-06-09 as #47"` but + can also be `"abandoned 2026-06-12, see planning/archived/2026-06-12-X"`. +- The body header (`**Status:** ...` etc.) **is removed** from existing + specs as part of migration. The frontmatter is the single source of + truth. The H1 title remains. + +### 5. `planning/README.md` — hand-maintained index + +One-line summary per artifact, grouped by lifecycle: + +```markdown +# Planning + +Specs and plans for `faststream-outbox` changes. See [CLAUDE.md](../CLAUDE.md#workflow) +for the per-feature workflow. + +## Active + +- **[docs-landing-and-comparison](active/2026-06-10-docs-landing-and-comparison-design.md)** + — Rewrite docs landing, reshape nav into Concepts/Guides/Reference, add a + Comparison page. +- **[planning-conventions](active/2026-06-10-planning-conventions-design.md)** + — This spec. Codify spec/plan boundary, add active/archived/templates, + migrate existing pairs. + +## Archived (shipped) + +- **[mkdocs-github-pages](archived/2026-06-09-mkdocs-github-pages-design.md)** + (#?, 2026-06-09) — Move docs hosting from Read the Docs to GitHub Pages. +- **[drain-test-flaky-fetch-observation](archived/2026-06-09-drain-test-flaky-fetch-observation-design.md)** + (#48, 2026-06-?) — Drain test waits via fetched recorder, not SQL poll. +- **[foreign-broker-relay](archived/2026-06-04-foreign-broker-relay-design.md)** + (#?, 2026-06-?) — Decorator-relay pattern with `OutboxSubscriber` as + source, three guardrails, docs push. +- **[faststream-0.7.1-testbroker-typing](archived/2026-06-04-faststream-0.7.1-testbroker-typing-design.md)** + (#?, 2026-06-?) — Type fixes for TestBroker against FastStream 0.7.1. +- **[faststream-0.7-migration](archived/2026-06-03-faststream-0.7-migration-design.md)** + (#?, 2026-06-?) — Migration to FastStream 0.7. +- **[all-extra-and-planning-dir](archived/2026-06-03-all-extra-and-planning-dir-design.md)** + (#?, 2026-06-?) — Introduce the `[all]` extras bundle and the + `planning/` directory itself. +``` + +The migration step (§8) fills in the actual PR numbers and merge dates by +reading `git log --grep=""` and the merge commits. + +### 6. Templates + +`planning/_templates/design.md`: + +```markdown +--- +status: draft +date: YYYY-MM-DD +slug: my-change +supersedes: null +superseded_by: null +pr: null +outcome: null +--- + +# Design: One-line capitalized title + +## Summary + +One paragraph. What changes, at the level a reader needs to decide if this +spec is worth reading in full. + +## Motivation + +Why now. What is broken or missing. Concrete observations / numbers, not +abstract complaints. Link to memory entries or earlier specs when relevant. + +## Non-goals + +What is deliberately out of scope and (when nontrivial) why. Each item is +a sentence; one line each. + +## Design + +### 1. + +What changes, in enough detail that a reader who has not seen the codebase +can follow. Code samples / diagrams welcome. + +### 2. + +... + +## Operations + +Out-of-repo steps (DNS, infra, external account changes). Omit if none. + +## Out of scope + +Already covered above under Non-goals if appropriate. Repeat-list of +explicitly-excluded follow-ups belongs here when the list is long. + +## Testing + +How we know it landed correctly. New pytest? Smoke check on live URL? +Lint pass? Be specific. + +## Risk + +What could go wrong, ranked by likelihood × impact. Mitigations. +``` + +`planning/_templates/plan.md`: + +```markdown +--- +status: draft +date: YYYY-MM-DD +slug: my-change +spec: my-change +pr: null +--- + +# — implementation plan + +> **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. + +**Goal:** One sentence — what shipping this plan achieves. No design +rationale; link to the spec for that. + +**Spec:** [`planning/active/YYYY-MM-DD-my-change-design.md`](./YYYY-MM-DD-my-change-design.md) + +**Branch:** `feat/my-change` (or `fix/`, `chore/`, etc.) + +**Commit strategy:** Per-task commits / single commit / squash on merge. +Whichever fits. + +--- + +### Task 1: + +**Files:** +- Modify: `path/to/file.py` +- Create: `path/to/new.py` + +One sentence on what this task accomplishes. No deeper reasoning — that's +in the spec. + +- [ ] **Step 1: ** + + Run / edit / verify command. Expected output. + +- [ ] **Step 2: ** + + ... + +- [ ] **Step 3: Commit** + + ```bash + git add path/to/file.py + git commit -m ": + + Co-Authored-By: Claude Opus 4.7 (1M context) " + ``` + +--- + +### Task 2: ... +``` + +Both templates are copy-and-rename, not generated. A `just new-spec` / +`just new-plan` target could automate the rename + date substitution, but +is **out of scope** here. + +### 7. Supersedes / superseded_by + +When a new spec overturns a decision in an earlier spec: + +1. The new spec sets `supersedes: ` in frontmatter and adds a + one-line `## Supersedes` section near the top explaining what changes + and why. +2. The old spec (in `archived/`) gets `superseded_by: ` set and + a `## Superseded by` callout at the top. +3. `status:` on the old spec flips to `superseded`. It stays in + `archived/` — the implementation that shipped still landed; the + *design conclusion* was later replaced. + +Cheap, manual, and visible. No automation. + +### 8. Migration of existing artifacts + +One-time, performed in the same PR that ships this spec. Per pair (six +pairs total): + +1. **Move both files** from `planning/specs/` and `planning/plans/` to + `planning/archived/`. The shared date-slug prefix in the filenames + preserves pairing. +2. **Replace the body header** (`**Status:** ...` / `**Date:** ...` / + `**Slug:** ...`) with YAML frontmatter at the top of the file. +3. **Set `status: shipped`** (or `superseded` where applicable — none in + the current six). +4. **Fill `pr:` and `outcome:`** by reading `git log --merges --grep=""` + and inspecting the merge commits visible in the git history. Recent + commit titles from the repo log already name the PRs (e.g. + `Merge pull request #48 from modern-python/fix/drain-test-flake-recorder` + for `drain-test-flaky-fetch-observation`). +5. **Sanity-check** that the spec/plan pair share a slug — if not, fix + the slug field rather than the filename. + +The migration touches twelve files, ~10 lines of frontmatter each, plus +the deletion of three body-header lines per file. No prose content is +rewritten. `git mv` preserves history for blame. + +Old empty directories `planning/specs/` and `planning/plans/` are removed +in the same commit (the `.gitkeep` files go too). The post-state matches +the tree in §2 exactly. + +### 9. CLAUDE.md update + +Two edits in the `## Workflow` section: + +1. **Update the per-feature pipeline path string** to reflect the new + `active/` directory: + > Per-feature: brainstorming → spec in + > `planning/active/YYYY-MM-DD--design.md` → writing-plans → + > plan in `planning/active/YYYY-MM-DD--plan.md` → executing- + > plans / subagent-driven-development → requesting-code-review → + > finishing-a-development-branch. + +2. **Append the spec/plan/architecture boundary** as a sub-paragraph + immediately after, lifted from §1 above. + +Nothing else in `CLAUDE.md` changes. + +## Out of scope (repeat list) + +Already named under Non-goals; repeated here for grep: + +- `just plans` index generator +- Trimming existing plans (promote design content back into specs) +- Relocating `planning/architecture/` out of `planning/` +- Frontmatter parsing CI checks +- Tiny-change lane for typo / dep-bump scope + +## Testing + +Configuration + content + file moves; correctness is checked by: + +- `just lint-ci` passes (markdown EOF + ruff on YAML formatting in the + Justfile if it changes — it does not in this spec). +- Every artifact under `planning/active/` and `planning/archived/` has + parseable YAML frontmatter (spot-checked manually on review; the cost + of a malformed block surfaces on read). +- `planning/README.md` links resolve — manual click-through on PR + preview. +- The post-migration tree exactly matches §2. + +No new pytest hooks. No new CI jobs. + +## Risk + +- **`git log` archaeology produces wrong PR numbers for older specs.** + Some of the six existing pairs may have shipped under squashed PRs + whose subjects do not mention the slug. Mitigation: the migration + step falls back to leaving `pr: null` and `outcome: "shipped, PR + unknown"` on any artifact where the merge commit cannot be identified + with confidence. Future merges fill the fields correctly because the + convention is in place. + +- **`git mv` history blame breakage on tooling that ignores `--follow`.** + GitHub Web UI follows renames in blame; some editor blame integrations + do not. Low practical impact — readers blaming a planning artifact + are usually looking for "who wrote this spec" not "what was the line + five revisions ago". `git log --follow planning/archived/` works + regardless. + +- **Frontmatter conflicts with mkdocs builds** if `planning/` ever gets + served by mkdocs. It does not today (`docs_dir: docs`), and there is + no plan to. If a future spec exposes `planning/` to mkdocs, the + frontmatter format we land here is already mkdocs-compatible. + +- **Convention drift on the next contributor.** Mitigated by the + templates — copy the file, fill the blanks. Material risk is + someone editing an existing template-shaped spec without the + frontmatter (because they grepped an older shipped one). Acceptable + loss; PR review catches it. + +- **The hand-maintained `README.md` index falls out of date.** A + contributor lands a spec and forgets to update the index. Acceptable: + PR review catches it the same way it catches a missing test. The + `just plans` automation in §"Non-goals" is the answer if drift + becomes chronic. diff --git a/planning/specs/2026-06-03-all-extra-and-planning-dir-design.md b/planning/archived/2026-06-03-all-extra-and-planning-dir-design.md similarity index 97% rename from planning/specs/2026-06-03-all-extra-and-planning-dir-design.md rename to planning/archived/2026-06-03-all-extra-and-planning-dir-design.md index 13dcc99..2991f33 100644 --- a/planning/specs/2026-06-03-all-extra-and-planning-dir-design.md +++ b/planning/archived/2026-06-03-all-extra-and-planning-dir-design.md @@ -1,8 +1,14 @@ -# Design: `all` aggregate extra + `planning/` workflow directory +--- +status: shipped +date: 2026-06-03 +slug: all-extra-and-planning-dir +supersedes: null +superseded_by: null +pr: "41" +outcome: merged 2026-06-03 as #41 +--- -**Date:** 2026-06-03 -**Status:** Approved -**Slug:** `all-extra-and-planning-dir` +# Design: `all` aggregate extra + `planning/` workflow directory ## Summary diff --git a/planning/plans/2026-06-03-all-extra-and-planning-dir-plan.md b/planning/archived/2026-06-03-all-extra-and-planning-dir-plan.md similarity index 99% rename from planning/plans/2026-06-03-all-extra-and-planning-dir-plan.md rename to planning/archived/2026-06-03-all-extra-and-planning-dir-plan.md index 5d81ed6..1ec3afa 100644 --- a/planning/plans/2026-06-03-all-extra-and-planning-dir-plan.md +++ b/planning/archived/2026-06-03-all-extra-and-planning-dir-plan.md @@ -1,3 +1,11 @@ +--- +status: shipped +date: 2026-06-03 +slug: all-extra-and-planning-dir +spec: all-extra-and-planning-dir +pr: "41" +--- + # `all` extra and `planning/` workflow dir — Implementation Plan > **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. diff --git a/planning/specs/2026-06-03-faststream-0.7-migration-design.md b/planning/archived/2026-06-03-faststream-0.7-migration-design.md similarity index 98% rename from planning/specs/2026-06-03-faststream-0.7-migration-design.md rename to planning/archived/2026-06-03-faststream-0.7-migration-design.md index 76a1cea..6df5182 100644 --- a/planning/specs/2026-06-03-faststream-0.7-migration-design.md +++ b/planning/archived/2026-06-03-faststream-0.7-migration-design.md @@ -1,8 +1,14 @@ -# Design: FastStream 0.7 migration +--- +status: shipped +date: 2026-06-03 +slug: faststream-0.7-migration +supersedes: null +superseded_by: null +pr: "42" +outcome: merged 2026-06-03 as #42 +--- -**Date:** 2026-06-03 -**Status:** Approved -**Slug:** `faststream-0.7-migration` +# Design: FastStream 0.7 migration ## Summary diff --git a/planning/plans/2026-06-03-faststream-0.7-migration-plan.md b/planning/archived/2026-06-03-faststream-0.7-migration-plan.md similarity index 99% rename from planning/plans/2026-06-03-faststream-0.7-migration-plan.md rename to planning/archived/2026-06-03-faststream-0.7-migration-plan.md index 448b1c5..431f59c 100644 --- a/planning/plans/2026-06-03-faststream-0.7-migration-plan.md +++ b/planning/archived/2026-06-03-faststream-0.7-migration-plan.md @@ -1,3 +1,11 @@ +--- +status: shipped +date: 2026-06-03 +slug: faststream-0.7-migration +spec: faststream-0.7-migration +pr: "42" +--- + # FastStream 0.7 Migration — Implementation Plan > **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. diff --git a/planning/specs/2026-06-04-faststream-0.7.1-testbroker-typing-design.md b/planning/archived/2026-06-04-faststream-0.7.1-testbroker-typing-design.md similarity index 98% rename from planning/specs/2026-06-04-faststream-0.7.1-testbroker-typing-design.md rename to planning/archived/2026-06-04-faststream-0.7.1-testbroker-typing-design.md index 53a9889..94d7186 100644 --- a/planning/specs/2026-06-04-faststream-0.7.1-testbroker-typing-design.md +++ b/planning/archived/2026-06-04-faststream-0.7.1-testbroker-typing-design.md @@ -1,8 +1,14 @@ -# FastStream 0.7.1 TestBroker typing alignment — design +--- +status: shipped +date: 2026-06-04 +slug: faststream-0.7.1-testbroker-typing +supersedes: null +superseded_by: null +pr: "43" +outcome: merged 2026-06-04 as #43 +--- -**Status:** Draft -**Date:** 2026-06-04 -**Slug:** `faststream-0.7.1-testbroker-typing` +# FastStream 0.7.1 TestBroker typing alignment — design ## Goal diff --git a/planning/plans/2026-06-04-faststream-0.7.1-testbroker-typing-plan.md b/planning/archived/2026-06-04-faststream-0.7.1-testbroker-typing-plan.md similarity index 98% rename from planning/plans/2026-06-04-faststream-0.7.1-testbroker-typing-plan.md rename to planning/archived/2026-06-04-faststream-0.7.1-testbroker-typing-plan.md index a4622a0..f2a75df 100644 --- a/planning/plans/2026-06-04-faststream-0.7.1-testbroker-typing-plan.md +++ b/planning/archived/2026-06-04-faststream-0.7.1-testbroker-typing-plan.md @@ -1,3 +1,11 @@ +--- +status: shipped +date: 2026-06-04 +slug: faststream-0.7.1-testbroker-typing +spec: faststream-0.7.1-testbroker-typing +pr: "43" +--- + # FastStream 0.7.1 TestBroker typing alignment — implementation plan > **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. diff --git a/planning/specs/2026-06-04-foreign-broker-relay-design.md b/planning/archived/2026-06-04-foreign-broker-relay-design.md similarity index 99% rename from planning/specs/2026-06-04-foreign-broker-relay-design.md rename to planning/archived/2026-06-04-foreign-broker-relay-design.md index dbbe952..e9ff046 100644 --- a/planning/specs/2026-06-04-foreign-broker-relay-design.md +++ b/planning/archived/2026-06-04-foreign-broker-relay-design.md @@ -1,8 +1,14 @@ -# Foreign-broker relay from `OutboxSubscriber` — design +--- +status: shipped +date: 2026-06-04 +slug: foreign-broker-relay +supersedes: null +superseded_by: null +pr: "44" +outcome: merged 2026-06-05 as #44 +--- -**Status:** Draft -**Date:** 2026-06-04 -**Slug:** `foreign-broker-relay` +# Foreign-broker relay from `OutboxSubscriber` — design ## Goal diff --git a/planning/plans/2026-06-04-foreign-broker-relay-plan.md b/planning/archived/2026-06-04-foreign-broker-relay-plan.md similarity index 99% rename from planning/plans/2026-06-04-foreign-broker-relay-plan.md rename to planning/archived/2026-06-04-foreign-broker-relay-plan.md index a50fcd1..15cb51e 100644 --- a/planning/plans/2026-06-04-foreign-broker-relay-plan.md +++ b/planning/archived/2026-06-04-foreign-broker-relay-plan.md @@ -1,3 +1,11 @@ +--- +status: shipped +date: 2026-06-04 +slug: foreign-broker-relay +spec: foreign-broker-relay +pr: "44" +--- + # Foreign-broker relay — implementation plan > **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. diff --git a/planning/specs/2026-06-09-drain-test-flaky-fetch-observation-design.md b/planning/archived/2026-06-09-drain-test-flaky-fetch-observation-design.md similarity index 97% rename from planning/specs/2026-06-09-drain-test-flaky-fetch-observation-design.md rename to planning/archived/2026-06-09-drain-test-flaky-fetch-observation-design.md index 5f7439b..7562e8d 100644 --- a/planning/specs/2026-06-09-drain-test-flaky-fetch-observation-design.md +++ b/planning/archived/2026-06-09-drain-test-flaky-fetch-observation-design.md @@ -1,3 +1,13 @@ +--- +status: shipped +date: 2026-06-09 +slug: drain-test-flaky-fetch-observation +supersedes: null +superseded_by: null +pr: "48" +outcome: merged 2026-06-10 as #48 +--- + # Drain test: replace SQL-poll flake with recorder observation ## Problem diff --git a/planning/plans/2026-06-09-drain-test-flaky-fetch-observation-plan.md b/planning/archived/2026-06-09-drain-test-flaky-fetch-observation-plan.md similarity index 98% rename from planning/plans/2026-06-09-drain-test-flaky-fetch-observation-plan.md rename to planning/archived/2026-06-09-drain-test-flaky-fetch-observation-plan.md index 981a79e..74b2fd5 100644 --- a/planning/plans/2026-06-09-drain-test-flaky-fetch-observation-plan.md +++ b/planning/archived/2026-06-09-drain-test-flaky-fetch-observation-plan.md @@ -1,3 +1,11 @@ +--- +status: shipped +date: 2026-06-09 +slug: drain-test-flaky-fetch-observation +spec: drain-test-flaky-fetch-observation +pr: "48" +--- + # Drain Test Flake Fix Implementation Plan > **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. diff --git a/planning/specs/2026-06-09-mkdocs-github-pages-design.md b/planning/archived/2026-06-09-mkdocs-github-pages-design.md similarity index 98% rename from planning/specs/2026-06-09-mkdocs-github-pages-design.md rename to planning/archived/2026-06-09-mkdocs-github-pages-design.md index d32652b..1b7c5e5 100644 --- a/planning/specs/2026-06-09-mkdocs-github-pages-design.md +++ b/planning/archived/2026-06-09-mkdocs-github-pages-design.md @@ -1,8 +1,14 @@ -# Design: Migrate docs hosting from Read the Docs to GitHub Pages +--- +status: shipped +date: 2026-06-09 +slug: mkdocs-github-pages +supersedes: null +superseded_by: null +pr: "45" +outcome: merged 2026-06-09 as #45 +--- -**Date:** 2026-06-09 -**Status:** Approved -**Slug:** `mkdocs-github-pages` +# Design: Migrate docs hosting from Read the Docs to GitHub Pages ## Summary diff --git a/planning/plans/2026-06-09-mkdocs-github-pages-plan.md b/planning/archived/2026-06-09-mkdocs-github-pages-plan.md similarity index 99% rename from planning/plans/2026-06-09-mkdocs-github-pages-plan.md rename to planning/archived/2026-06-09-mkdocs-github-pages-plan.md index 7ebd128..88e1b11 100644 --- a/planning/plans/2026-06-09-mkdocs-github-pages-plan.md +++ b/planning/archived/2026-06-09-mkdocs-github-pages-plan.md @@ -1,3 +1,11 @@ +--- +status: shipped +date: 2026-06-09 +slug: mkdocs-github-pages +spec: mkdocs-github-pages +pr: "45" +--- + # Migrate Docs Hosting from Read the Docs to GitHub Pages — Implementation Plan > **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. diff --git a/planning/plans/.gitkeep b/planning/plans/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/planning/specs/.gitkeep b/planning/specs/.gitkeep deleted file mode 100644 index e69de29..0000000