diff --git a/CLAUDE.md b/CLAUDE.md index 8ce52af..847ee4c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,7 +38,7 @@ BaseBootstrapper (abc.ABC) ### Key design decisions -Recent design context, bugs, and convention rationale: see the bug-audit findings in `planning/audits/` and the post-work reflections in `planning/retros/` (the audit arcs themselves are bundled under `planning/changes/archive/`). +Recent design context, bugs, and convention rationale: see the bug-audit findings in `planning/audits/` and the post-work reflections in `planning/retros/` (the audit arcs themselves are bundled under `planning/changes/`). - **Optional dependencies**: Each instrument checks for its optional package via `import_checker.py` (`importlib.util.find_spec`). Instruments are skipped silently if the package is absent. Optional packages are imported inside `if import_checker.is_X_installed:` blocks; static analyzers that don't model this guard will report spurious "possibly unbound" diagnostics — the project uses `ty` which handles the pattern correctly. - **Instrument skip ordering**: `BaseBootstrapper.__init__` runs `instrument_type.is_configured(config)` first (silent skip if the user's config indicates the instrument shouldn't run — populates `bootstrapper.skipped_instruments: list[tuple[type, str]]`); then `check_dependencies()` (emits `InstrumentDependencyMissingWarning` only for configured-but-dep-missing — the genuine deployment surprise); then instantiates. One `logger.info` summary line at the end lists configured + skipped instruments via `BaseBootstrapper.build_summary()`; that method is also publicly callable for post-construction debugging. Uses stdlib `logging` so it composes cleanly with the user's logging setup and with pytest's `caplog`. @@ -63,13 +63,13 @@ See `[project.optional-dependencies]` in `pyproject.toml` for the full extras ma ## Workflow -Per-feature: brainstorming → spec in `planning/changes/active/YYYY-MM-DD.NN-/design.md` → writing-plans → plan in `planning/changes/active/YYYY-MM-DD.NN-/plan.md` → executing-plans / subagent-driven-development → requesting-code-review → finishing-a-development-branch. Each change is a folder bundle; `` is a kebab-case description, not a story ID; `.NN` is a zero-padded intra-day counter that breaks same-date ties so the timeline sorts stably. On merge, the bundle moves to `planning/changes/archive/` with `status: shipped`, `pr:`, and `outcome:` filled, **and the change promotes its conclusions into the affected `architecture/.md`** — that hand-edit is what keeps `architecture/` true. See [`planning/README.md`](planning/README.md) for the conventions + index and [`planning/_templates/`](planning/_templates/) for copy-and-fill starting points. +Per-feature: brainstorming → spec in `planning/changes/YYYY-MM-DD.NN-/design.md` → writing-plans → plan in `planning/changes/YYYY-MM-DD.NN-/plan.md` → executing-plans / subagent-driven-development → requesting-code-review → finishing-a-development-branch. Each change is a folder bundle; `` is a kebab-case description, not a story ID; `.NN` is a zero-padded intra-day counter that breaks same-date ties so the timeline sorts stably. The implementing PR sets `status: shipped` and fills `pr` / `outcome` in the branch, alongside the code and promotes its conclusions into the affected `architecture/.md` — that hand-edit keeps `architecture/` true and is the only ship-time step; there is no folder move. The change listing is generated — run `just index`. See [`planning/README.md`](planning/README.md) for the conventions and [`planning/_templates/`](planning/_templates/) for copy-and-fill starting points. -**Spec** (`design.md`) captures the *thinking* — why, what the design is, trade-offs, scope. Written before code; rarely revised after merge. **Plan** (`plan.md`) captures the *sequencing* — the ordered checklist an executor walks; references the spec for the "why". **`architecture/`** captures the *invariants* of shipped systems — the living truth, promoted from a change on merge. A plan paragraph that would still read correctly with all task numbers and checkboxes removed is design content and belongs in the spec. +**Spec** (`design.md`) captures the *thinking* — why, what the design is, trade-offs, scope. Written before code; rarely revised after merge. **Plan** (`plan.md`) captures the *sequencing* — the ordered checklist an executor walks; references the spec for the "why". **`architecture/`** captures the *invariants* of shipped systems — the living truth, promoted in the implementing PR alongside the code. A plan paragraph that would still read correctly with all task numbers and checkboxes removed is design content and belongs in the spec. **Three lanes.** Scale the artifact to the change. **Full** — a `design.md` + `plan.md` bundle — for real design judgment, a new file/module, a public-API change, cross-cutting/multi-file work, or non-trivial test design. **Lightweight** — a single `change.md` — for small-but-real changes (≲30 LOC net, ≤2 files, no new file, no public-API change, a single straightforward test). **Tiny** — no bundle, just a conventional commit — for a typo, dep bump, linter/formatter/CI tweak, a mechanical rename, or a single-line config change. Heavier lane wins on ambiguity; a `change.md` that outgrows its lane splits into `design.md` + `plan.md`. -Design docs and implementation plans live under `planning/` (not under `docs/`, so they're excluded from the mkdocs site automatically). When superpowers skills default to `docs/superpowers/specs/` or `docs/superpowers/plans/`, use the change bundle under `planning/changes/active/` here instead. +Design docs and implementation plans live under `planning/` (not under `docs/`, so they're excluded from the mkdocs site automatically). When superpowers skills default to `docs/superpowers/specs/` or `docs/superpowers/plans/`, use the change bundle under `planning/changes/` here instead. ## Code style diff --git a/Justfile b/Justfile index 1551691..ac4c482 100644 --- a/Justfile +++ b/Justfile @@ -16,6 +16,10 @@ lint-ci: uv run ruff check --no-fix uv run ty check +# Print the planning change index (grouped by status) to stdout. +index: + uv run python planning/index.py + test *args: uv run --no-sync pytest {{ args }} diff --git a/planning/README.md b/planning/README.md index 5abd272..fa80468 100644 --- a/planning/README.md +++ b/planning/README.md @@ -7,33 +7,35 @@ at the repo root; this directory records *how it got there*. ## Conventions > This section is the portable convention — identical across the -> modern-python repos. The Index below is repo-specific. To adopt elsewhere, +> modern-python repos. The generated change listing (`just index`) and the `## Other` pointers below are repo-local. To adopt elsewhere, > copy this section plus [`_templates/`](_templates/) and point that repo's > `CLAUDE.md` Workflow + truth home at it. ### Two axes, never mixed - **`architecture/` (repo root) — the present.** One file per capability, - living prose, updated whenever a change ships. The truth home. + living prose, updated in the same PR that ships the change. The truth home. - **`planning/changes/` — the past-and-pending.** One folder per change, - frozen once shipped. + kept in place after ship. -Shipping a change **promotes** its conclusions into the affected -`architecture/.md` by hand, then archives the bundle. That -hand-edit is what keeps `architecture/` true; the archived bundle carries the -*why*. +A change **promotes** its conclusions into the affected +`architecture/.md` by hand **in the implementing PR, alongside the +code** — the edit rides in the same diff and is reviewed with it, never applied +as a separate post-merge step. That hand-edit is what keeps `architecture/` +true; the bundle stays in `changes/` as the *why*. ### Change bundles -A change is a folder `changes/active/YYYY-MM-DD.NN-/`: +A change is a folder `changes/YYYY-MM-DD.NN-/`: - `YYYY-MM-DD` — proposal date; `.NN` — zero-padded intra-day counter (`.01`, `.02`, …) that breaks same-date ties so the timeline sorts stably. - `` — kebab-case description, not a story ID. -On merge the folder moves to `changes/archive/` with `status: shipped`, `pr:`, -and `outcome:` filled, and its line moves from **Active** to **Archived** in -the Index below. +`summary` is written when the change is created (it is the change's +one-liner). The implementing PR then sets `status: shipped` and fills `pr` +and `outcome` **in the branch**, alongside the code and the `architecture/` +promotion — no post-merge bookkeeping, no folder move. ### Three lanes @@ -62,44 +64,16 @@ Templates live in [`_templates/`](_templates/). ### Frontmatter `design.md` / `change.md`: `status` (draft|approved|shipped|superseded), -`date`, `slug`, `supersedes`, `superseded_by`, `pr`, `outcome`. -`plan.md`: `status`, `date`, `slug`, `spec`, `pr`. Files in `architecture/` -carry **no** frontmatter — living prose, dated by git. +`date`, `slug`, `summary` (single line), `supersedes`, `superseded_by`, `pr`, +`outcome`. `plan.md`: `status`, `date`, `slug`, `spec`, `pr`. Files in +`architecture/` carry **no** frontmatter — living prose, dated by git. ## Index -### Active - -_None._ - -### Archived (shipped) - -- **[portable-planning-convention](changes/archive/2026-06-13.01-portable-planning-convention/design.md)** - (#120, 2026-06-13) — Adopt the portable two-axis convention: `architecture/` - truth home + `changes/` bundles, per-arc bundling of the audit arcs, fresh - Index. -- **[mkdocs-github-pages](changes/archive/2026-06-09.01-mkdocs-github-pages/design.md)** - (#112–#115, 2026-06-09) — Docs hosting moved from Read the Docs to GitHub - Actions + Pages. -- **[bug-audit-v2](changes/archive/2026-06-05.01-bug-audit-v2/design.md)** - (#108–#110, 2026-06-05) — 26 findings (UX · logic · security · tests) shipped - across three themed PRs. -- **[deferred-refactors](changes/archive/2026-06-01.03-deferred-refactors/design.md)** - (#96–#103, 2026-06-01) — The 20 deferred items from the 2026-05-31 audit - (REF/TEST/LOW) across eight PRs. -- **[fastmcp-bootstrapper](changes/archive/2026-06-01.02-fastmcp-bootstrapper/design.md)** - (2026-06-01) — New `FastMcpBootstrapper` mirroring microbootstrap's fastmcp - support. -- **[instrument-skip-rework](changes/archive/2026-06-01.01-instrument-skip-rework/design.md)** - (2026-06-01) — Replace `InstrumentNotReadyWarning` with a pre-instantiation - config check + summary log. *Partially superseded by - [stdlib-logging-and-build-summary](changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/design.md).* -- **[stdlib-logging-and-build-summary](changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/design.md)** - (#107, 2026-06-02) — Stdlib `logging` in `bootstrappers/base.py` + public - `build_summary()`. -- **[audit-implementation](changes/archive/2026-05-31.01-audit-implementation/design.md)** - (#89–#95, 2026-05-31) — Criticals (CRIT-1..3) + design issues (DES-1..5) + - paired tests across seven sequenced PRs. +The change listing is **generated**, not maintained — run `just index` to +print it (grouped by `status`: In progress / Shipped / Superseded). The +frontmatter in each bundle is the single source of truth; there is no +committed copy to drift. ## Other diff --git a/planning/_templates/change.md b/planning/_templates/change.md index 0fe24c0..7ffec26 100644 --- a/planning/_templates/change.md +++ b/planning/_templates/change.md @@ -2,6 +2,7 @@ status: draft date: YYYY-MM-DD slug: my-change +summary: One line — shown in the generated index. Fill at ship time. supersedes: null superseded_by: null pr: null diff --git a/planning/_templates/design.md b/planning/_templates/design.md index fb0fe5b..b9e11c9 100644 --- a/planning/_templates/design.md +++ b/planning/_templates/design.md @@ -2,6 +2,7 @@ status: draft date: YYYY-MM-DD slug: my-change +summary: One line — shown in the generated index. Fill at ship time. supersedes: null superseded_by: null pr: null diff --git a/planning/changes/archive/2026-05-31.01-audit-implementation/design.md b/planning/changes/2026-05-31.01-audit-implementation/design.md similarity index 99% rename from planning/changes/archive/2026-05-31.01-audit-implementation/design.md rename to planning/changes/2026-05-31.01-audit-implementation/design.md index dcd215a..9f434bc 100644 --- a/planning/changes/archive/2026-05-31.01-audit-implementation/design.md +++ b/planning/changes/2026-05-31.01-audit-implementation/design.md @@ -2,6 +2,7 @@ status: shipped date: 2026-05-31 slug: audit-implementation +summary: Criticals (CRIT-1..3) + design issues (DES-1..5) + paired tests across seven sequenced PRs. supersedes: null superseded_by: null pr: null diff --git a/planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr1-crit1-redoc-root-path.md b/planning/changes/2026-05-31.01-audit-implementation/plan-pr1-crit1-redoc-root-path.md similarity index 100% rename from planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr1-crit1-redoc-root-path.md rename to planning/changes/2026-05-31.01-audit-implementation/plan-pr1-crit1-redoc-root-path.md diff --git a/planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr2-crit2-otel-shutdown.md b/planning/changes/2026-05-31.01-audit-implementation/plan-pr2-crit2-otel-shutdown.md similarity index 100% rename from planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr2-crit2-otel-shutdown.md rename to planning/changes/2026-05-31.01-audit-implementation/plan-pr2-crit2-otel-shutdown.md diff --git a/planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr3-crit3-idempotent-teardown.md b/planning/changes/2026-05-31.01-audit-implementation/plan-pr3-crit3-idempotent-teardown.md similarity index 100% rename from planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr3-crit3-idempotent-teardown.md rename to planning/changes/2026-05-31.01-audit-implementation/plan-pr3-crit3-idempotent-teardown.md diff --git a/planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr4-des4-des5-small-cleanups.md b/planning/changes/2026-05-31.01-audit-implementation/plan-pr4-des4-des5-small-cleanups.md similarity index 100% rename from planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr4-des4-des5-small-cleanups.md rename to planning/changes/2026-05-31.01-audit-implementation/plan-pr4-des4-des5-small-cleanups.md diff --git a/planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr5-des3-config-method-semantics.md b/planning/changes/2026-05-31.01-audit-implementation/plan-pr5-des3-config-method-semantics.md similarity index 100% rename from planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr5-des3-config-method-semantics.md rename to planning/changes/2026-05-31.01-audit-implementation/plan-pr5-des3-config-method-semantics.md diff --git a/planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr6-des2-otel-fields-mixin.md b/planning/changes/2026-05-31.01-audit-implementation/plan-pr6-des2-otel-fields-mixin.md similarity index 100% rename from planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr6-des2-otel-fields-mixin.md rename to planning/changes/2026-05-31.01-audit-implementation/plan-pr6-des2-otel-fields-mixin.md diff --git a/planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr7-des1-generic-instruments.md b/planning/changes/2026-05-31.01-audit-implementation/plan-pr7-des1-generic-instruments.md similarity index 100% rename from planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr7-des1-generic-instruments.md rename to planning/changes/2026-05-31.01-audit-implementation/plan-pr7-des1-generic-instruments.md diff --git a/planning/changes/archive/2026-06-01.01-instrument-skip-rework/design.md b/planning/changes/2026-06-01.01-instrument-skip-rework/design.md similarity index 99% rename from planning/changes/archive/2026-06-01.01-instrument-skip-rework/design.md rename to planning/changes/2026-06-01.01-instrument-skip-rework/design.md index 22d910b..29f251d 100644 --- a/planning/changes/archive/2026-06-01.01-instrument-skip-rework/design.md +++ b/planning/changes/2026-06-01.01-instrument-skip-rework/design.md @@ -2,6 +2,7 @@ status: shipped date: 2026-06-01 slug: instrument-skip-rework +summary: Replace `InstrumentNotReadyWarning` with a pre-instantiation config check + summary log. supersedes: null superseded_by: stdlib-logging-and-build-summary pr: null diff --git a/planning/changes/archive/2026-06-01.01-instrument-skip-rework/plan.md b/planning/changes/2026-06-01.01-instrument-skip-rework/plan.md similarity index 100% rename from planning/changes/archive/2026-06-01.01-instrument-skip-rework/plan.md rename to planning/changes/2026-06-01.01-instrument-skip-rework/plan.md diff --git a/planning/changes/archive/2026-06-01.02-fastmcp-bootstrapper/design.md b/planning/changes/2026-06-01.02-fastmcp-bootstrapper/design.md similarity index 99% rename from planning/changes/archive/2026-06-01.02-fastmcp-bootstrapper/design.md rename to planning/changes/2026-06-01.02-fastmcp-bootstrapper/design.md index 5f4c559..943655a 100644 --- a/planning/changes/archive/2026-06-01.02-fastmcp-bootstrapper/design.md +++ b/planning/changes/2026-06-01.02-fastmcp-bootstrapper/design.md @@ -2,6 +2,7 @@ status: shipped date: 2026-06-01 slug: fastmcp-bootstrapper +summary: New `FastMcpBootstrapper` mirroring microbootstrap's fastmcp support. supersedes: null superseded_by: null pr: null diff --git a/planning/changes/archive/2026-06-01.02-fastmcp-bootstrapper/plan.md b/planning/changes/2026-06-01.02-fastmcp-bootstrapper/plan.md similarity index 100% rename from planning/changes/archive/2026-06-01.02-fastmcp-bootstrapper/plan.md rename to planning/changes/2026-06-01.02-fastmcp-bootstrapper/plan.md diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/design.md b/planning/changes/2026-06-01.03-deferred-refactors/design.md similarity index 99% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/design.md rename to planning/changes/2026-06-01.03-deferred-refactors/design.md index 59d3ed0..fe3ea78 100644 --- a/planning/changes/archive/2026-06-01.03-deferred-refactors/design.md +++ b/planning/changes/2026-06-01.03-deferred-refactors/design.md @@ -2,6 +2,7 @@ status: shipped date: 2026-06-01 slug: deferred-refactors +summary: The 20 deferred items from the 2026-05-31 audit (REF/TEST/LOW) across eight PRs. supersedes: null superseded_by: null pr: null diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr10-test-gap-fill.md b/planning/changes/2026-06-01.03-deferred-refactors/plan-pr10-test-gap-fill.md similarity index 100% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr10-test-gap-fill.md rename to planning/changes/2026-06-01.03-deferred-refactors/plan-pr10-test-gap-fill.md diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr11-logging-cleanup.md b/planning/changes/2026-06-01.03-deferred-refactors/plan-pr11-logging-cleanup.md similarity index 100% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr11-logging-cleanup.md rename to planning/changes/2026-06-01.03-deferred-refactors/plan-pr11-logging-cleanup.md diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr12-base-layer-cleanup.md b/planning/changes/2026-06-01.03-deferred-refactors/plan-pr12-base-layer-cleanup.md similarity index 100% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr12-base-layer-cleanup.md rename to planning/changes/2026-06-01.03-deferred-refactors/plan-pr12-base-layer-cleanup.md diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr13-frozen-setattr.md b/planning/changes/2026-06-01.03-deferred-refactors/plan-pr13-frozen-setattr.md similarity index 100% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr13-frozen-setattr.md rename to planning/changes/2026-06-01.03-deferred-refactors/plan-pr13-frozen-setattr.md diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr14-faststream-timeout.md b/planning/changes/2026-06-01.03-deferred-refactors/plan-pr14-faststream-timeout.md similarity index 100% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr14-faststream-timeout.md rename to planning/changes/2026-06-01.03-deferred-refactors/plan-pr14-faststream-timeout.md diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr15-naming-pass.md b/planning/changes/2026-06-01.03-deferred-refactors/plan-pr15-naming-pass.md similarity index 100% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr15-naming-pass.md rename to planning/changes/2026-06-01.03-deferred-refactors/plan-pr15-naming-pass.md diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr16-post-retro-hygiene.md b/planning/changes/2026-06-01.03-deferred-refactors/plan-pr16-post-retro-hygiene.md similarity index 100% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr16-post-retro-hygiene.md rename to planning/changes/2026-06-01.03-deferred-refactors/plan-pr16-post-retro-hygiene.md diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr8-low-1-2-sentry-micro.md b/planning/changes/2026-06-01.03-deferred-refactors/plan-pr8-low-1-2-sentry-micro.md similarity index 100% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr8-low-1-2-sentry-micro.md rename to planning/changes/2026-06-01.03-deferred-refactors/plan-pr8-low-1-2-sentry-micro.md diff --git a/planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr9-otel-touch-ups.md b/planning/changes/2026-06-01.03-deferred-refactors/plan-pr9-otel-touch-ups.md similarity index 100% rename from planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr9-otel-touch-ups.md rename to planning/changes/2026-06-01.03-deferred-refactors/plan-pr9-otel-touch-ups.md diff --git a/planning/changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/design.md b/planning/changes/2026-06-02.01-stdlib-logging-and-build-summary/design.md similarity index 99% rename from planning/changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/design.md rename to planning/changes/2026-06-02.01-stdlib-logging-and-build-summary/design.md index 7a4f9e1..da145de 100644 --- a/planning/changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/design.md +++ b/planning/changes/2026-06-02.01-stdlib-logging-and-build-summary/design.md @@ -2,6 +2,7 @@ status: shipped date: 2026-06-02 slug: stdlib-logging-and-build-summary +summary: Stdlib `logging` in `bootstrappers/base.py` + public `build_summary()`. supersedes: instrument-skip-rework superseded_by: null pr: "107" diff --git a/planning/changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/plan.md b/planning/changes/2026-06-02.01-stdlib-logging-and-build-summary/plan.md similarity index 100% rename from planning/changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/plan.md rename to planning/changes/2026-06-02.01-stdlib-logging-and-build-summary/plan.md diff --git a/planning/changes/archive/2026-06-05.01-bug-audit-v2/design.md b/planning/changes/2026-06-05.01-bug-audit-v2/design.md similarity index 99% rename from planning/changes/archive/2026-06-05.01-bug-audit-v2/design.md rename to planning/changes/2026-06-05.01-bug-audit-v2/design.md index 4291591..9066760 100644 --- a/planning/changes/archive/2026-06-05.01-bug-audit-v2/design.md +++ b/planning/changes/2026-06-05.01-bug-audit-v2/design.md @@ -2,6 +2,7 @@ status: shipped date: 2026-06-05 slug: bug-audit-v2 +summary: 26 findings (UX · logic · security · tests) shipped across three themed PRs. supersedes: null superseded_by: null pr: null diff --git a/planning/changes/archive/2026-06-05.01-bug-audit-v2/plan-pr1-lifecycle.md b/planning/changes/2026-06-05.01-bug-audit-v2/plan-pr1-lifecycle.md similarity index 100% rename from planning/changes/archive/2026-06-05.01-bug-audit-v2/plan-pr1-lifecycle.md rename to planning/changes/2026-06-05.01-bug-audit-v2/plan-pr1-lifecycle.md diff --git a/planning/changes/archive/2026-06-05.01-bug-audit-v2/plan-pr2-config-security.md b/planning/changes/2026-06-05.01-bug-audit-v2/plan-pr2-config-security.md similarity index 100% rename from planning/changes/archive/2026-06-05.01-bug-audit-v2/plan-pr2-config-security.md rename to planning/changes/2026-06-05.01-bug-audit-v2/plan-pr2-config-security.md diff --git a/planning/changes/archive/2026-06-05.01-bug-audit-v2/plan-pr3-hygiene-ci.md b/planning/changes/2026-06-05.01-bug-audit-v2/plan-pr3-hygiene-ci.md similarity index 100% rename from planning/changes/archive/2026-06-05.01-bug-audit-v2/plan-pr3-hygiene-ci.md rename to planning/changes/2026-06-05.01-bug-audit-v2/plan-pr3-hygiene-ci.md diff --git a/planning/changes/archive/2026-06-09.01-mkdocs-github-pages/design.md b/planning/changes/2026-06-09.01-mkdocs-github-pages/design.md similarity index 99% rename from planning/changes/archive/2026-06-09.01-mkdocs-github-pages/design.md rename to planning/changes/2026-06-09.01-mkdocs-github-pages/design.md index d37188f..cc0159f 100644 --- a/planning/changes/archive/2026-06-09.01-mkdocs-github-pages/design.md +++ b/planning/changes/2026-06-09.01-mkdocs-github-pages/design.md @@ -2,6 +2,7 @@ status: shipped date: 2026-06-09 slug: mkdocs-github-pages +summary: Docs hosting moved from Read the Docs to GitHub Actions + Pages. supersedes: null superseded_by: null pr: null diff --git a/planning/changes/archive/2026-06-09.01-mkdocs-github-pages/plan.md b/planning/changes/2026-06-09.01-mkdocs-github-pages/plan.md similarity index 100% rename from planning/changes/archive/2026-06-09.01-mkdocs-github-pages/plan.md rename to planning/changes/2026-06-09.01-mkdocs-github-pages/plan.md diff --git a/planning/changes/archive/2026-06-13.01-portable-planning-convention/design.md b/planning/changes/2026-06-13.01-portable-planning-convention/design.md similarity index 99% rename from planning/changes/archive/2026-06-13.01-portable-planning-convention/design.md rename to planning/changes/2026-06-13.01-portable-planning-convention/design.md index 67e7824..e786d29 100644 --- a/planning/changes/archive/2026-06-13.01-portable-planning-convention/design.md +++ b/planning/changes/2026-06-13.01-portable-planning-convention/design.md @@ -2,6 +2,7 @@ status: shipped date: 2026-06-13 slug: portable-planning-convention +summary: Adopt the portable two-axis convention: `architecture/` truth home + `changes/` bundles, per-arc bundling of the audit arcs, fresh Index. supersedes: null superseded_by: null pr: "120" diff --git a/planning/changes/archive/2026-06-13.01-portable-planning-convention/plan.md b/planning/changes/2026-06-13.01-portable-planning-convention/plan.md similarity index 86% rename from planning/changes/archive/2026-06-13.01-portable-planning-convention/plan.md rename to planning/changes/2026-06-13.01-portable-planning-convention/plan.md index 1fe69ce..afd8f04 100644 --- a/planning/changes/archive/2026-06-13.01-portable-planning-convention/plan.md +++ b/planning/changes/2026-06-13.01-portable-planning-convention/plan.md @@ -51,7 +51,7 @@ already committed there). ### Task 1: Scaffold the new `planning/` skeleton + copy templates **Files:** -- Create: `planning/changes/active/.gitkeep`, `planning/changes/archive/` (via bundles later) +- Create: `planning/changes/active/.gitkeep`, `planning/changes/` (via bundles later) - Create: `planning/audits/`, `planning/retros/` - Create: `planning/_templates/{design,plan,change}.md` (copied byte-identical) - Create: `planning/deferred.md` @@ -212,24 +212,24 @@ needs to understand the capability *now* — not change history. cd /Users/kevinsmith/src/pypi/lite-bootstrap # instrument-skip-rework (2026-06-01.01) - mkdir -p planning/changes/archive/2026-06-01.01-instrument-skip-rework - git mv planning/specs/2026-06-01-instrument-skip-rework-design.md planning/changes/archive/2026-06-01.01-instrument-skip-rework/design.md - git mv planning/plans/2026-06-01-instrument-skip-rework.md planning/changes/archive/2026-06-01.01-instrument-skip-rework/plan.md + mkdir -p planning/changes/2026-06-01.01-instrument-skip-rework + git mv planning/specs/2026-06-01-instrument-skip-rework-design.md planning/changes/2026-06-01.01-instrument-skip-rework/design.md + git mv planning/plans/2026-06-01-instrument-skip-rework.md planning/changes/2026-06-01.01-instrument-skip-rework/plan.md # fastmcp-bootstrapper (2026-06-01.02) - mkdir -p planning/changes/archive/2026-06-01.02-fastmcp-bootstrapper - git mv planning/specs/2026-06-01-fastmcp-bootstrapper-design.md planning/changes/archive/2026-06-01.02-fastmcp-bootstrapper/design.md - git mv planning/plans/2026-06-01-fastmcp-bootstrapper.md planning/changes/archive/2026-06-01.02-fastmcp-bootstrapper/plan.md + mkdir -p planning/changes/2026-06-01.02-fastmcp-bootstrapper + git mv planning/specs/2026-06-01-fastmcp-bootstrapper-design.md planning/changes/2026-06-01.02-fastmcp-bootstrapper/design.md + git mv planning/plans/2026-06-01-fastmcp-bootstrapper.md planning/changes/2026-06-01.02-fastmcp-bootstrapper/plan.md # stdlib-logging-and-build-summary (2026-06-02.01) - mkdir -p planning/changes/archive/2026-06-02.01-stdlib-logging-and-build-summary - git mv planning/specs/2026-06-02-stdlib-logging-and-build-summary-design.md planning/changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/design.md - git mv planning/plans/2026-06-02-stdlib-logging-and-build-summary.md planning/changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/plan.md + mkdir -p planning/changes/2026-06-02.01-stdlib-logging-and-build-summary + git mv planning/specs/2026-06-02-stdlib-logging-and-build-summary-design.md planning/changes/2026-06-02.01-stdlib-logging-and-build-summary/design.md + git mv planning/plans/2026-06-02-stdlib-logging-and-build-summary.md planning/changes/2026-06-02.01-stdlib-logging-and-build-summary/plan.md # mkdocs-github-pages (2026-06-09.01) - mkdir -p planning/changes/archive/2026-06-09.01-mkdocs-github-pages - git mv planning/specs/2026-06-09-mkdocs-github-actions-design.md planning/changes/archive/2026-06-09.01-mkdocs-github-pages/design.md - git mv planning/plans/2026-06-09-mkdocs-github-actions-plan.md planning/changes/archive/2026-06-09.01-mkdocs-github-pages/plan.md + mkdir -p planning/changes/2026-06-09.01-mkdocs-github-pages + git mv planning/specs/2026-06-09-mkdocs-github-actions-design.md planning/changes/2026-06-09.01-mkdocs-github-pages/design.md + git mv planning/plans/2026-06-09-mkdocs-github-actions-plan.md planning/changes/2026-06-09.01-mkdocs-github-pages/plan.md ``` - [ ] **Step 2: Prepend frontmatter to each `design.md`** @@ -338,7 +338,7 @@ needs to understand the capability *now* — not change history. - [ ] **Step 4: Fix any internal cross-links broken by the rename** - Run: `grep -rn "instrument-skip-rework\|2026-06-01-fastmcp\|2026-06-02-stdlib\|2026-06-09-mkdocs" planning/changes/archive/` + Run: `grep -rn "instrument-skip-rework\|2026-06-01-fastmcp\|2026-06-02-stdlib\|2026-06-09-mkdocs" planning/changes/` For each hit that points at an old `planning/specs|plans/...` path or a sibling doc's old filename, update it to the new bundle path (`./design.md`, `./plan.md`, or `..//design.md`). The @@ -349,7 +349,7 @@ needs to understand the capability *now* — not change history. Run: ```bash - for f in planning/changes/archive/*/design.md planning/changes/archive/*/plan.md; do + for f in planning/changes/*/design.md planning/changes/*/plan.md; do python3 -c "import sys,yaml; t=open('$f').read(); assert t.startswith('---'); yaml.safe_load(t.split('---')[1]); print('OK $f')" done ``` @@ -378,35 +378,35 @@ needs to understand the capability *now* — not change history. cd /Users/kevinsmith/src/pypi/lite-bootstrap # Arc 1: audit-implementation (2026-05-31.01) — sequencing → design.md, pr1..7 grouped - mkdir -p planning/changes/archive/2026-05-31.01-audit-implementation - git mv planning/specs/2026-05-31-audit-implementation-sequencing.md planning/changes/archive/2026-05-31.01-audit-implementation/design.md - git mv planning/plans/2026-05-31-pr1-crit1-redoc-root-path.md planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr1-crit1-redoc-root-path.md - git mv planning/plans/2026-05-31-pr2-crit2-otel-shutdown.md planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr2-crit2-otel-shutdown.md - git mv planning/plans/2026-05-31-pr3-crit3-idempotent-teardown.md planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr3-crit3-idempotent-teardown.md - git mv planning/plans/2026-06-01-pr4-des4-des5-small-cleanups.md planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr4-des4-des5-small-cleanups.md - git mv planning/plans/2026-06-01-pr5-des3-config-method-semantics.md planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr5-des3-config-method-semantics.md - git mv planning/plans/2026-06-01-pr6-des2-otel-fields-mixin.md planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr6-des2-otel-fields-mixin.md - git mv planning/plans/2026-06-01-pr7-des1-generic-instruments.md planning/changes/archive/2026-05-31.01-audit-implementation/plan-pr7-des1-generic-instruments.md + mkdir -p planning/changes/2026-05-31.01-audit-implementation + git mv planning/specs/2026-05-31-audit-implementation-sequencing.md planning/changes/2026-05-31.01-audit-implementation/design.md + git mv planning/plans/2026-05-31-pr1-crit1-redoc-root-path.md planning/changes/2026-05-31.01-audit-implementation/plan-pr1-crit1-redoc-root-path.md + git mv planning/plans/2026-05-31-pr2-crit2-otel-shutdown.md planning/changes/2026-05-31.01-audit-implementation/plan-pr2-crit2-otel-shutdown.md + git mv planning/plans/2026-05-31-pr3-crit3-idempotent-teardown.md planning/changes/2026-05-31.01-audit-implementation/plan-pr3-crit3-idempotent-teardown.md + git mv planning/plans/2026-06-01-pr4-des4-des5-small-cleanups.md planning/changes/2026-05-31.01-audit-implementation/plan-pr4-des4-des5-small-cleanups.md + git mv planning/plans/2026-06-01-pr5-des3-config-method-semantics.md planning/changes/2026-05-31.01-audit-implementation/plan-pr5-des3-config-method-semantics.md + git mv planning/plans/2026-06-01-pr6-des2-otel-fields-mixin.md planning/changes/2026-05-31.01-audit-implementation/plan-pr6-des2-otel-fields-mixin.md + git mv planning/plans/2026-06-01-pr7-des1-generic-instruments.md planning/changes/2026-05-31.01-audit-implementation/plan-pr7-des1-generic-instruments.md # Arc 2: deferred-refactors (2026-06-01.03) — sequencing → design.md, pr8..16 grouped - mkdir -p planning/changes/archive/2026-06-01.03-deferred-refactors - git mv planning/specs/2026-06-01-deferred-refactors-sequencing.md planning/changes/archive/2026-06-01.03-deferred-refactors/design.md - git mv planning/plans/2026-06-01-pr8-low-1-2-sentry-micro.md planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr8-low-1-2-sentry-micro.md - git mv planning/plans/2026-06-01-pr9-otel-touch-ups.md planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr9-otel-touch-ups.md - git mv planning/plans/2026-06-01-pr10-test-gap-fill.md planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr10-test-gap-fill.md - git mv planning/plans/2026-06-01-pr11-logging-cleanup.md planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr11-logging-cleanup.md - git mv planning/plans/2026-06-01-pr12-base-layer-cleanup.md planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr12-base-layer-cleanup.md - git mv planning/plans/2026-06-01-pr13-frozen-setattr.md planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr13-frozen-setattr.md - git mv planning/plans/2026-06-01-pr14-faststream-timeout.md planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr14-faststream-timeout.md - git mv planning/plans/2026-06-01-pr15-naming-pass.md planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr15-naming-pass.md - git mv planning/plans/2026-06-01-pr16-post-retro-hygiene.md planning/changes/archive/2026-06-01.03-deferred-refactors/plan-pr16-post-retro-hygiene.md + mkdir -p planning/changes/2026-06-01.03-deferred-refactors + git mv planning/specs/2026-06-01-deferred-refactors-sequencing.md planning/changes/2026-06-01.03-deferred-refactors/design.md + git mv planning/plans/2026-06-01-pr8-low-1-2-sentry-micro.md planning/changes/2026-06-01.03-deferred-refactors/plan-pr8-low-1-2-sentry-micro.md + git mv planning/plans/2026-06-01-pr9-otel-touch-ups.md planning/changes/2026-06-01.03-deferred-refactors/plan-pr9-otel-touch-ups.md + git mv planning/plans/2026-06-01-pr10-test-gap-fill.md planning/changes/2026-06-01.03-deferred-refactors/plan-pr10-test-gap-fill.md + git mv planning/plans/2026-06-01-pr11-logging-cleanup.md planning/changes/2026-06-01.03-deferred-refactors/plan-pr11-logging-cleanup.md + git mv planning/plans/2026-06-01-pr12-base-layer-cleanup.md planning/changes/2026-06-01.03-deferred-refactors/plan-pr12-base-layer-cleanup.md + git mv planning/plans/2026-06-01-pr13-frozen-setattr.md planning/changes/2026-06-01.03-deferred-refactors/plan-pr13-frozen-setattr.md + git mv planning/plans/2026-06-01-pr14-faststream-timeout.md planning/changes/2026-06-01.03-deferred-refactors/plan-pr14-faststream-timeout.md + git mv planning/plans/2026-06-01-pr15-naming-pass.md planning/changes/2026-06-01.03-deferred-refactors/plan-pr15-naming-pass.md + git mv planning/plans/2026-06-01-pr16-post-retro-hygiene.md planning/changes/2026-06-01.03-deferred-refactors/plan-pr16-post-retro-hygiene.md # Arc 3: bug-audit-v2 (2026-06-05.01) — sequencing → design.md, pr1..3 grouped - mkdir -p planning/changes/archive/2026-06-05.01-bug-audit-v2 - git mv planning/specs/2026-06-05-bug-audit-v2-sequencing.md planning/changes/archive/2026-06-05.01-bug-audit-v2/design.md - git mv planning/plans/2026-06-05-pr1-lifecycle.md planning/changes/archive/2026-06-05.01-bug-audit-v2/plan-pr1-lifecycle.md - git mv planning/plans/2026-06-05-pr2-config-security.md planning/changes/archive/2026-06-05.01-bug-audit-v2/plan-pr2-config-security.md - git mv planning/plans/2026-06-05-pr3-hygiene-ci.md planning/changes/archive/2026-06-05.01-bug-audit-v2/plan-pr3-hygiene-ci.md + mkdir -p planning/changes/2026-06-05.01-bug-audit-v2 + git mv planning/specs/2026-06-05-bug-audit-v2-sequencing.md planning/changes/2026-06-05.01-bug-audit-v2/design.md + git mv planning/plans/2026-06-05-pr1-lifecycle.md planning/changes/2026-06-05.01-bug-audit-v2/plan-pr1-lifecycle.md + git mv planning/plans/2026-06-05-pr2-config-security.md planning/changes/2026-06-05.01-bug-audit-v2/plan-pr2-config-security.md + git mv planning/plans/2026-06-05-pr3-hygiene-ci.md planning/changes/2026-06-05.01-bug-audit-v2/plan-pr3-hygiene-ci.md ``` - [ ] **Step 2: `git mv` audits → `audits/` and retros → `retros/`** @@ -482,9 +482,9 @@ needs to understand the capability *now* — not change history. Run: ```bash - for f in planning/changes/archive/2026-05-31.01-audit-implementation/design.md \ - planning/changes/archive/2026-06-01.03-deferred-refactors/design.md \ - planning/changes/archive/2026-06-05.01-bug-audit-v2/design.md; do + for f in planning/changes/2026-05-31.01-audit-implementation/design.md \ + planning/changes/2026-06-01.03-deferred-refactors/design.md \ + planning/changes/2026-06-05.01-bug-audit-v2/design.md; do python3 -c "import yaml; t=open('$f').read(); assert t.startswith('---'); yaml.safe_load(t.split('---')[1]); print('OK $f')" done ls planning/specs planning/plans @@ -583,26 +583,26 @@ needs to understand the capability *now* — not change history. ### Archived (shipped) - - **[mkdocs-github-pages](changes/archive/2026-06-09.01-mkdocs-github-pages/design.md)** + - **[mkdocs-github-pages](changes/2026-06-09.01-mkdocs-github-pages/design.md)** (#112–#115, 2026-06-09) — Docs hosting moved from Read the Docs to GitHub Actions + Pages. - - **[bug-audit-v2](changes/archive/2026-06-05.01-bug-audit-v2/design.md)** + - **[bug-audit-v2](changes/2026-06-05.01-bug-audit-v2/design.md)** (#108–#110, 2026-06-05) — 26 findings (UX · logic · security · tests) shipped across three themed PRs. - - **[deferred-refactors](changes/archive/2026-06-01.03-deferred-refactors/design.md)** + - **[deferred-refactors](changes/2026-06-01.03-deferred-refactors/design.md)** (#96–#103, 2026-06-01) — The 20 deferred items from the 2026-05-31 audit (REF/TEST/LOW) across eight PRs. - - **[fastmcp-bootstrapper](changes/archive/2026-06-01.02-fastmcp-bootstrapper/design.md)** + - **[fastmcp-bootstrapper](changes/2026-06-01.02-fastmcp-bootstrapper/design.md)** (2026-06-01) — New `FastMcpBootstrapper` mirroring microbootstrap's fastmcp support. - - **[instrument-skip-rework](changes/archive/2026-06-01.01-instrument-skip-rework/design.md)** + - **[instrument-skip-rework](changes/2026-06-01.01-instrument-skip-rework/design.md)** (2026-06-01) — Replace `InstrumentNotReadyWarning` with a pre-instantiation config check + summary log. *Partially superseded by - [stdlib-logging-and-build-summary](changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/design.md).* - - **[stdlib-logging-and-build-summary](changes/archive/2026-06-02.01-stdlib-logging-and-build-summary/design.md)** + [stdlib-logging-and-build-summary](changes/2026-06-02.01-stdlib-logging-and-build-summary/design.md).* + - **[stdlib-logging-and-build-summary](changes/2026-06-02.01-stdlib-logging-and-build-summary/design.md)** (#107, 2026-06-02) — Stdlib `logging` in `bootstrappers/base.py` + public `build_summary()`. - - **[audit-implementation](changes/archive/2026-05-31.01-audit-implementation/design.md)** + - **[audit-implementation](changes/2026-05-31.01-audit-implementation/design.md)** (#89–#95, 2026-05-31) — Criticals (CRIT-1..3) + design issues (DES-1..5) + paired tests across seven sequenced PRs. @@ -666,7 +666,7 @@ needs to understand the capability *now* — not change history. ```markdown ## Workflow - Per-feature: brainstorming → spec in `planning/changes/active/YYYY-MM-DD.NN-/design.md` → writing-plans → plan in `planning/changes/active/YYYY-MM-DD.NN-/plan.md` → executing-plans / subagent-driven-development → requesting-code-review → finishing-a-development-branch. Each change is a folder bundle; `` is a kebab-case description, not a story ID; `.NN` is a zero-padded intra-day counter that breaks same-date ties so the timeline sorts stably. On merge, the bundle moves to `planning/changes/archive/` with `status: shipped`, `pr:`, and `outcome:` filled, **and the change promotes its conclusions into the affected `architecture/.md`** — that hand-edit is what keeps `architecture/` true. See [`planning/README.md`](planning/README.md) for the conventions + index and [`planning/_templates/`](planning/_templates/) for copy-and-fill starting points. + Per-feature: brainstorming → spec in `planning/changes/active/YYYY-MM-DD.NN-/design.md` → writing-plans → plan in `planning/changes/active/YYYY-MM-DD.NN-/plan.md` → executing-plans / subagent-driven-development → requesting-code-review → finishing-a-development-branch. Each change is a folder bundle; `` is a kebab-case description, not a story ID; `.NN` is a zero-padded intra-day counter that breaks same-date ties so the timeline sorts stably. On merge, the bundle moves to `planning/changes/` with `status: shipped`, `pr:`, and `outcome:` filled, **and the change promotes its conclusions into the affected `architecture/.md`** — that hand-edit is what keeps `architecture/` true. See [`planning/README.md`](planning/README.md) for the conventions + index and [`planning/_templates/`](planning/_templates/) for copy-and-fill starting points. **Spec** (`design.md`) captures the *thinking* — why, what the design is, trade-offs, scope. Written before code; rarely revised after merge. **Plan** (`plan.md`) captures the *sequencing* — the ordered checklist an executor walks; references the spec for the "why". **`architecture/`** captures the *invariants* of shipped systems — the living truth, promoted from a change on merge. A plan paragraph that would still read correctly with all task numbers and checkboxes removed is design content and belongs in the spec. @@ -730,7 +730,7 @@ needs to understand the capability *now* — not change history. Run: ```bash echo "--- stale pointers ---" - grep -rn "planning/specs\|planning/plans\|lightweight-plan-template" --include="*.md" --include="justfile" . | grep -vE "planning/changes/archive/" || echo "clean" + grep -rn "planning/specs\|planning/plans\|lightweight-plan-template" --include="*.md" --include="justfile" . | grep -vE "planning/changes/" || echo "clean" echo "--- final planning tree ---" ls -R planning/ architecture/ ``` @@ -771,7 +771,7 @@ its final archived state: ```bash git mv planning/changes/active/2026-06-13.01-portable-planning-convention \ - planning/changes/archive/2026-06-13.01-portable-planning-convention + planning/changes/2026-06-13.01-portable-planning-convention ``` `status: shipped`, `pr: "120"`, and `outcome:` are set in this bundle's diff --git a/planning/changes/active/.gitkeep b/planning/changes/active/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/planning/index.py b/planning/index.py new file mode 100644 index 0000000..6621d3f --- /dev/null +++ b/planning/index.py @@ -0,0 +1,95 @@ +# ruff: noqa: INP001, D212 # planning/ is not a Python package; D212/D213 conflict differs from faststream-outbox +""" +Generate the planning change index from bundle frontmatter. + +Run via ``just index``. Globs ``planning/changes/*/``, reads each bundle's +``design.md`` (falling back to ``change.md``) frontmatter, and prints a +Markdown listing grouped by lifecycle status to stdout. Never writes a file: +the listing is a query over the bundles, not a committed artifact. +""" + +import pathlib +import sys + + +CHANGES_DIR = pathlib.Path(__file__).parent / "changes" +GROUPS: tuple[tuple[str, tuple[str, ...]], ...] = ( + ("In progress", ("draft", "approved")), + ("Shipped", ("shipped",)), + ("Superseded", ("superseded",)), +) + + +def parse_frontmatter(text: str) -> dict[str, str]: + """Parse a single-line-scalar YAML frontmatter block into a dict.""" + lines = text.splitlines() + if not lines or lines[0].strip() != "---": + return {} + fields: dict[str, str] = {} + for line in lines[1:]: + if line.strip() == "---": + break + key, sep, value = line.partition(": ") + if not sep: + continue + cleaned = value.strip().strip('"').strip("'") + fields[key.strip()] = "" if cleaned == "null" else cleaned + return fields + + +def load_bundles() -> list[dict[str, str]]: + """Read every bundle's spec frontmatter under ``CHANGES_DIR``.""" + bundles: list[dict[str, str]] = [] + for bundle in sorted(CHANGES_DIR.iterdir()): + if not bundle.is_dir(): + continue + spec = bundle / "design.md" + if not spec.exists(): + spec = bundle / "change.md" + if not spec.exists(): + continue + fields = parse_frontmatter(spec.read_text(encoding="utf-8")) + fields["path"] = f"changes/{bundle.name}/{spec.name}" + fields["name"] = bundle.name + bundles.append(fields) + return bundles + + +def format_row(bundle: dict[str, str]) -> str: + """Render one bundle as a Markdown list item.""" + slug = bundle.get("slug", "?") + path = bundle.get("path", "") + pr = bundle.get("pr") or "—" + date = bundle.get("date", "") + summary = bundle.get("summary") or "(no summary)" + line = f"- **[{slug}]({path})** (#{pr}, {date}) — {summary}" + if bundle.get("supersedes"): + line += f" _(supersedes {bundle['supersedes']})_" + if bundle.get("superseded_by"): + line += f" _(superseded by {bundle['superseded_by']})_" + return line + + +def render(bundles: list[dict[str, str]]) -> str: + """Render the full grouped Markdown listing.""" + out = ["# Change index", "", "_Generated by `just index` — do not edit._", ""] + for title, statuses in GROUPS: + out += [f"## {title}", ""] + rows = sorted( + (b for b in bundles if b.get("status") in statuses), + key=lambda b: b.get("name", ""), + reverse=True, + ) + out += [format_row(b) for b in rows] if rows else ["_None._"] + out.append("") + return "\n".join(out).rstrip() + "\n" + + +def main() -> int: + """Print the listing to stdout.""" + sys.stdout.write(render(load_bundles())) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())