Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions todo/changelog-directory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Replace `CHANGELOG.md` with a `changelog/` directory

**Priority:** P2
**Status:** open

## Problem

Every PR adds its entry at the top of `## Unreleased` in `CHANGELOG.md`, so any
two concurrent PRs conflict on the same lines. The file is also over 2000 lines
and keeps growing.

## Proposal

Replace the single file with a directory:

```
changelog/
README.md <- the current CHANGELOG preamble: versioning convention,
entry-style rules
unreleased/
<PR>.md <- one file per changelog-worthy PR, named by PR number
<version>.md <- retrofitted released sections, one file per release
```

- A PR adds `changelog/unreleased/<PR>.md` instead of editing a shared file —
PR numbers are unique, so concurrent PRs can never conflict. A PR with
several entries puts them all in its one file. The `**BREAKING CHANGES:**`
marker keeps its meaning; at release time it is found by scanning
`changelog/unreleased/`.
- Entry ordering: filenames sort by PR number descending. Today's file is in
*merge* order, which this does not reproduce exactly — a PR opened earlier
can merge after one opened later. That deviation is accepted: PR-number
order is deterministic and conflict-free, and exact merge order can be
recovered later by generating from Git history
([changelog-from-git-history.md](./changelog-from-git-history.md)).
- Releasing: concatenate `unreleased/*.md` (descending) into
`changelog/<version>.md` and delete the entry files. Git does not store
empty directories, so `unreleased/` needs a permanent file (`.gitkeep` or a
one-line `README.md`).
- Retrofit: released sections move as one file per version
(`changelog/0.44.0.md`, …). Splitting history per PR would be churn with no
benefit — conflicts only ever happen in `unreleased` — and pre-convention
entries have no PR number to name a file by.
- Entries stay in the Markdown subset they already use (paragraphs, list
items, inline code, bold, PR links). Publishing the changelog on the website
([changelog-website.md](./changelog-website.md)) needs to render entries with
a small self-hosted parser, so the subset is the convention, not an accident.

## Tasks

- [ ] Create `changelog/README.md` from the `CHANGELOG.md` preamble
- [ ] Retrofit released sections as `changelog/<version>.md`
- [ ] Create `changelog/unreleased/` with its permanent file and move any
unreleased entries into per-PR files
- [ ] Delete `CHANGELOG.md`, or leave a short stub pointing at `changelog/`
- [ ] Update `AGENTS.md` §8.3 (entry workflow) and §8.4 (release step) and
`CONTRIBUTING.md` to describe the directory

## Related

- [changelog-website.md](./changelog-website.md) — consumes this structure
- [changelog-from-git-history.md](./changelog-from-git-history.md) — may
eventually replace this structure
48 changes: 48 additions & 0 deletions todo/changelog-from-git-history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Investigate generating the changelog from Git history

**Priority:** P4
**Status:** open

## Problem

Even as per-PR files ([changelog-directory.md](./changelog-directory.md)),
changelog entries are authored by hand while the same information — commits,
diffs, PR links — already exists in Git history. It may be possible to remove
the `changelog/` directory and derive the release history directly:

```
Git history -> changelog generator -> FunctionalScript website
```

This is an investigation, not a commitment: summarizing diffs at build time
would make the published notes non-deterministic and unreviewed, and Git
history is immutable, so a badly worded source could never be fixed — while a
committed entry can be fixed by a cleanup PR. The `**BREAKING CHANGES:**`
marker also drives version bumps, and that signal must stay reviewed.

## Proposal

Evaluate at least these designs before removing `changelog/`:

1. **Commit-message extraction.** The entry lives in the squash/merge commit
message (e.g. a `Changelog:` trailer, reviewed as part of the PR). The
generator deterministically extracts trailers between release tags — no
summarization, reviewed text, `changelog/` genuinely redundant.
2. **Authoring assistant.** A tool drafts the entry from the PR's diff at PR
time; the reviewed result is still committed as a `changelog/` file. The
generator stays out of the build; `changelog/` remains the source of truth.
3. **Build-time summarization.** The generator reads commits and diffs and
writes the prose itself. Only acceptable if the output is deterministic and
there is a reviewed override mechanism — which tends to reinvent
`changelog/`.

Decide on criteria: determinism of the published pages, where review happens,
how a published mistake gets fixed, and where the breaking-change signal for
versioning comes from.

## Related

- [changelog-directory.md](./changelog-directory.md) — the structure this
would replace
- [changelog-website.md](./changelog-website.md) — the consumer that must not
care which source feeds it
33 changes: 33 additions & 0 deletions todo/changelog-website.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Publish the changelog on the website

**Priority:** P4
**Status:** blocked
**Blocked by:** [Replace `CHANGELOG.md` with a `changelog/` directory](./changelog-directory.md)

## Problem

The release history lives only in the repository. Users of the package should
be able to read it on the FunctionalScript website as an index of releases and
a page per release.

## Proposal

Extend the website generator (`fjs/website`) to read the `changelog/`
directory and emit an index page plus one page per release. The repository
remains the source of truth; the website is presentation.

The main cost is rendering: the repo has no Markdown parser. Either write a
small self-hosted parser for the entry subset (paragraphs, list items, inline
code, bold, links — all the current entries use), or reconsider the entry
format. The BNF machinery is a natural fit for the parser.

## Tasks

- [ ] Parser for the changelog Markdown subset
- [ ] Release index page and per-release pages in `fjs/website`
- [ ] Link the changelog from the landing page

## Related

- [changelog-directory.md](./changelog-directory.md) — defines the structure
and the Markdown subset this consumes
Loading