--- name: iflow-history-update description: >- Update the changelog when landing an issue: append a bullet to [Unreleased], or promote it to a release section after a version bump. disable-model-invocation: true issue-flow-version: 0.4.2a4 --- # issue-flow — history update Use this skill to decide the changelog bullet as part of `/iflow-close`. It never runs on its own schedule; it is driven by the "update HISTORY" step, and does not run when the user passed `nohistory` / `skip history`. The write happens now, on the issue branch, so the bullet lands in the PR commit. ### MODEL & EXECUTION DIRECTIVE **Profile: economy** — Prioritize speed and token economy over deep reasoning. In Cursor: use **Auto** or a fast model before invoking this step. Keep scope tight to what this step requires. ## Preconditions 1. The changelog file (`HISTORY.md`) exists at the **project root**. If it does not, **skip** this step, print "no `HISTORY.md` — skipping changelog update" and continue the rest of `/iflow-close`. Never create the file from this skill. 2. The file is in **Keep a Changelog** shape: a top-level `## [Unreleased]` heading, with released versions below as `## [x.y.z] - YYYY-MM-DD` headings. If the shape does not match, **stop and report the mismatch** instead of guessing — let the user fix the file or pass `nohistory`. ## Inputs from `/iflow-close` | From | Used for | |---|---| | Issue number `N` | Reference suffix on the new bullet, e.g. `(#42)`. | | Issue title (from `.issueflows/01-current-issues/issue_original.md`) | Default bullet summary. | | `log "..."` / `note "..."` input token | Override the bullet summary verbatim. | | Version-bump outcome (from step 2 of `/iflow-close`) | Decides **append** vs **promote** (see below). | ## Operation modes ### A. No version bump — append to `[Unreleased]` 1. Read `HISTORY.md`. Locate the first `## [Unreleased]` heading. The block ends at the next `## [` heading (or EOF). 2. Compose the new bullet: ``` - . (#) ``` Summary = `log "..."` override if provided, else the issue title with sentence case, trailing period trimmed before the `.` we add. 3. Append the bullet to the end of the Unreleased bullet list. Preserve existing formatting (blank lines, list markers). Do not reorder existing entries. 4. Write the change without a confirm prompt (`confirm_changelog_update` is false; same as the `yolo` token's history behaviour). Still report what was written. ### B. Version bump happened — promote `[Unreleased]` to a new release section Only runs when step 2 of `/iflow-close` actually changed `pyproject.toml` to a new version `NEW_VERSION`. 1. Determine `NEW_VERSION` (e.g. read from `pyproject.toml`, or from the `uv version` command output). Determine `TODAY` as `YYYY-MM-DD` in the user's local timezone. 2. Read `HISTORY.md`. Find `## [Unreleased]`. 3. Compose the new bullet (same shape as mode A). If `[Unreleased]` was empty when the bump happened, still create the new release section with this bullet inside it — a version bump implies a release, and the focus issue's bullet is always meaningful. 4. Rename the existing heading from `## [Unreleased]` to `## [] - ` and add the new bullet at the end of that section's bullet list. 5. Prepend a fresh, empty `## [Unreleased]` section above the just-closed release, with one blank line separating them: ```markdown ## [Unreleased] ## [NEW_VERSION] - TODAY - …existing bullets from before the promote… - (#N) ``` 6. Write the change without a confirm prompt (`confirm_changelog_update` is false). Still report what was written. ## Conflict resolution — keep both bullet sets When an unrelated PR lands on the default branch while this issue is in flight, both branches add a bullet to the **same** `## [Unreleased]` section and git cannot merge it. That is bookkeeping, not a design decision, so it has exactly one documented answer — used by `/iflow-close`'s sync step and by `/iflow-cycle`'s parallel coordinator, so every agent produces the same file. **Resolvable only when all of these hold:** 1. the conflicted file is `HISTORY.md` and **nothing else** is conflicted; 2. every conflict region sits under `## [Unreleased]`; 3. both sides contain **only** list items (plus blank / wrapped continuation lines). **Resolution:** keep **all** bullets. The bullets already on the default branch keep their positions; this issue's bullet goes **last** — identical to mode A's append, so a resolved conflict looks exactly like having written the bullet after the other one landed. Byte-identical bullets collapse to one. **Refuse and stop** (a human decides) when the conflict touches any other file, an existing bullet was edited or deleted, a heading was renamed, or a `## [Unreleased]` section was promoted to a release section on either side. **Fast path:** `issue-flow agent sync-branch --json` applies exactly this rule during the rebase in `/iflow-close` step 6 and aborts on anything else. Prefer it over hand-editing conflict markers. ## Staging When `/iflow-close` reaches its commit step: - Stage `HISTORY.md` alongside the issue's other changes so the bullet is in the **same commit** that feeds the PR. - If a version bump also ran, `HISTORY.md` is staged in the same commit as `pyproject.toml` (and `uv.lock` if it changed). ## Constraints - Read/write only `HISTORY.md` at the project root. Do not touch any other file from this skill. - Never create `HISTORY.md` from scratch — scaffolding a starter changelog is out of scope for `issue-flow init` / `update`. - **Timing:** this skill runs only from `/iflow-close` step 3 (before commit / push / PR update). Write even when a draft PR already exists from `/iflow-build` early PR. **Never** propose updating `HISTORY.md` after close has finished or after merge. - Preserve existing formatting conventions (bullet style, sentence case, trailing punctuation). Match the style of the nearest existing entries when in doubt. - The new bullet's `(#)` suffix is always GitHub issue `#N`, matching the focus issue's number in `.issueflows/01-current-issues/issue_original.md`.