From 476787fec9b777955a8ce057caf53ee428c47e63 Mon Sep 17 00:00:00 2001 From: qer Date: Fri, 7 Aug 2026 02:23:37 +0800 Subject: [PATCH] docs(agents): rework changelog curation rules for the user-facing changelog (#2708) * docs(agents): rework changelog curation rules for the user-facing changelog * docs(agents): refine catch-all wording and add reviewer notes to the changelog preview * docs(agents): surface folded entries at the sync review checkpoint --- .agents/skills/gen-changesets/SKILL.md | 2 ++ .agents/skills/pre-changelog/SKILL.md | 3 +++ .agents/skills/sync-changelog/SKILL.md | 23 +++++++++++++++++++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.agents/skills/gen-changesets/SKILL.md b/.agents/skills/gen-changesets/SKILL.md index 44123a6fa..ad64295f8 100644 --- a/.agents/skills/gen-changesets/SKILL.md +++ b/.agents/skills/gen-changesets/SKILL.md @@ -13,6 +13,8 @@ All other `@moonshot-ai/*` packages are treated as internal packages, including `@moonshot-ai/pi-tui` is a special internal package: it is a private fork (`private: true`) that is never published, but it keeps its own changelog through changesets. It is an exception to Core Rule 4 — see the dedicated section below. +Only the CLI changelog gets a curated, user-facing presentation (the docs-site changelog sync). The SDK and other internal package changelogs are raw changesets output kept for version history — nobody curates them, so write those entries honestly and technically; their wording does not need to suit end users. + ## Core Rules 1. **Inspect the actual changes first.** Use `git status` / `git diff --name-only` to identify which packages were actually changed. diff --git a/.agents/skills/pre-changelog/SKILL.md b/.agents/skills/pre-changelog/SKILL.md index 4937ea2a0..4f1f83710 100644 --- a/.agents/skills/pre-changelog/SKILL.md +++ b/.agents/skills/pre-changelog/SKILL.md @@ -39,6 +39,7 @@ Process the version block exactly as `sync-changelog` does for the docs site, bu - **Strip** (`sync-changelog` step 3): drop the H1, the `### Patch Changes` / `### Minor Changes` / `### Major Changes` subheadings, PR links, and commit-hash links; keep only each entry's body text. The `Thanks [@user](...)!` credit (including the multi-author form) must be removed every time. Within each entry, drop SDK-only and provider-internal sentences (SDK capability mapping / API exposure, provider wire-format mechanics, internal XML markers, hook/event payload mechanics such as what an event reports or carries) and keep only the user-facing effect and required constraints. - **Merge and deduplicate** (`sync-changelog` step 4): merge micro-tweaks to the same surface into one higher-level entry; when three or more fixes target the same UI area or the same class of problem, merge them into one higher-level fix entry (do not merge broad or genuinely distinct fixes); and drop a server/API entry that only backs a web feature already listed. +- **Collapse low-signal entries** (`sync-changelog` step 4): keep standalone only entries that pass both gates — the reader-action test (the reader must do or re-evaluate something) and the channel test (the product cannot push it into the user's path: hidden controls, habit invalidations, capabilities users would not know to seek — a control merely sitting in the UI is not surfacing, users do not explore). Polish keeps only must-react items; experiences the product shows at the moment of need (recovery cards, post-install guidance) fold. Fixes keep only behavior-change entries (readers must update a habit, config, or workaround); loud failures fold (the fix itself notifies the victim), and silent past damage folds too — the changelog does not repair the past, and a notice that names no locatable instance and no realistic action is noise, not diligence. Section sizes follow density defaults (about 2 polish, 3 fixes) that yield to genuinely qualifying entries — flag the overflow for the reviewer instead of folding to hit the number. Fold everything else into one catch-all line placed last under 修复 — `修复了一些已知问题。` (or `修复了一些已知问题,并做了若干细节优化。` when non-fix entries were also collapsed; when nothing folded is a fix, place it under 优化 instead as `做了若干细节优化和内部改进。`), followed by a separate pointer sentence: `更详细的变更记录见 [GitHub](https://github.com/MoonshotAI/kimi-code/blob/main/apps/kimi-code/CHANGELOG.md)。` (file link, no version anchor; before the release PR merges, the target does not yet contain this version's block — expected for a preview). - **Classify** (`sync-changelog` step 4): bucket into Features / Bug Fixes / Polish / Refactors / Other; order within each section by reader value (in Polish, user-visible improvements before protocol/internal adjustments). - **Translate** (`sync-changelog` step 6): translate entry bodies to Chinese; keep one sentence per entry with a parallel rhythm within a section; section headings become 新功能 / 修复 / 优化 / 重构 / 其他. @@ -48,6 +49,8 @@ If an upstream entry is not in English, flag it and stop (changeset entries must Print the preview directly. Use `(预览)` as the heading because the version is not released yet. Write `无` for empty sections. Do not write any file. +After the preview block, append a reviewer-only section titled `### 审稿参考(不进入文档)`: list every entry folded into the catch-all (short English title, one line each), note any section that exceeds the density defaults, and flag borderline calls for the reviewer to confirm. This breakdown is how reviewers see what was folded — before merge, the catch-all pointer's target does not yet contain the version's block. Never write this section into the docs pages. + The preview is pasted into chat tools (for example Lark), where relative docs links do not resolve. Rewrite every docs link to its absolute published URL: map `../.md[#anchor]` to `https://moonshotai.github.io/kimi-code/zh/.html[#anchor]` — for example `../configuration/config-files.md#loop-control` → `https://moonshotai.github.io/kimi-code/zh/configuration/config-files.html#loop-control`. Never emit raw relative paths, and never wrap a link in backticks; code-style the link text inside the brackets instead ([`loop_control`](...)). ``` diff --git a/.agents/skills/sync-changelog/SKILL.md b/.agents/skills/sync-changelog/SKILL.md index ac9ff1604..e8fbd021a 100644 --- a/.agents/skills/sync-changelog/SKILL.md +++ b/.agents/skills/sync-changelog/SKILL.md @@ -128,12 +128,20 @@ Public-text rule: do not copy real internal endpoints, key names, account names, Before classifying, merge related entries and drop redundant ones from the user-facing changelog: +- **Curate for end users: collapse low-signal entries into one catch-all line.** The docs changelog is the only curated, user-facing outlet; the full entry list always remains in the upstream package changelog, so hiding detail here loses nothing. Apply two gates to every candidate entry. Gate 1, the reader-action test: **after reading this, is there something the reader must do, or something they must re-evaluate?** Gate 2, the channel test: **is the changelog the only channel that can deliver this?** The changelog is the channel of last resort — when the product itself surfaces the information in context, at the moment of need, to exactly the affected users, the entry is redundant no matter how real the improvement is. "Surfaced" means pushed into the user's path, not merely present on screen: an event-triggered card, prompt, or post-install screen forces the encounter, while a toggle, menu item, command, or settings page only waits to be found. Users do not explore — a capability that lives only in ambient UI is effectively undiscoverable, so the changelog must announce it. What in-product surfacing cannot deliver: hidden controls (env vars, config keys, opt-out flags nobody would find unprompted), invalidations of existing habits or expectations (in-product discovery comes as confusion), and capabilities users would not know to seek. An entry that fails either gate folds. Anchor both gates to the changelog's reader, never to the bug's victim: someone who hit a loud failure does not need the changelog to confirm the fix — the product working again is the notification — and a reader who never hit it gets nothing from the entry. + - `Features`: keep when users would try it or must react to it — new capabilities create demand readers did not know to seek. Collapse only behavior that takes effect solely behind an experimental flag. + - `Polish`: keep only must-react items — a notification users may want to turn off, a behavior change to a command they already use, a default flip with an opt-out. Fold improved experiences the product surfaces in context (recovery cards, post-install guidance, progress or status displays): they are discovered at the moment of need, and pre-reading about them helps nobody. Also fold subtle or transient tweaks (status wording, spacing, animations) and internal-behavior adjustments — nobody acts on them. + - `Bug Fixes`: keep only **behavior-change** fixes — the fix changes how something works going forward, so readers must update a habit, a config, or a widely-adopted workaround. Everything else folds, for one of two opposite reasons. Loud failures (crashes, refusals, interrupted runs): the fix itself notifies whoever was hit — announcement value falls as bug visibility rises. Silent past damage (dropped data, wrong results the user never noticed): the changelog cannot repair the past, and in this product the notice names no locatable instance and no realistic action — users cannot enumerate which old sessions were affected, and they do not audit finished sessions; a "some past outputs may be wrong" line is anxiety without an outlet, not diligence. The rare exception is a retrospective notice with a concrete, locatable action (for example rotating a token after a credential-handling flaw); keep those. Never keep a fix merely because it was severe, and never keep one because the bug class feels important. + - Do not grade entries by engineering importance. Severity and effort are already represented upstream; the curated changelog is not a credit ledger — its only job is to change what the reader does or knows. + - **Density, not quota.** Standalone sections stay short so the changelog actually gets read — as a default, expect about 2 Polish and 3 Bug Fixes entries per version, while `Features` is gated by the test alone and has no count. The defaults yield whenever more entries genuinely pass the reader-action test: keep them and flag the overflow for the human reviewer; never fold a qualifying entry just to hit the number, and never pad a section to reach it. The reviewer owns the final cutoff — the curator's job is to surface the borderline calls, not to resolve them silently. + - Everything else collapses into a single catch-all bullet placed last under `Bug Fixes`: `Fix several known issues.` When entries beyond fixes were also collapsed, use `Fix several known issues and make various refinements.` instead (Chinese: `修复了一些已知问题。` / `修复了一些已知问题,并做了若干细节优化。`). End the catch-all line with a pointer to the upstream file so folded entries stay reachable, phrased as a separate short sentence — `See the [changelog on GitHub](https://github.com/MoonshotAI/kimi-code/blob/main/apps/kimi-code/CHANGELOG.md) for more technical entries.` (Chinese: `更详细的变更记录见 [GitHub](https://github.com/MoonshotAI/kimi-code/blob/main/apps/kimi-code/CHANGELOG.md)。`). Link the file itself, never a per-version anchor — GitHub's generated heading anchors are fragile. Keep the pointer wording restrained ("more technical entries"): upstream only contains changes that received a changeset, so never claim the list is complete. + - If no fix survives, the `Bug Fixes` section is the catch-all line alone; if the whole version has no user-facing change, the version block is a single section with that line. Match the catch-all to what was folded — never claim fixes that did not happen: when the folded entries include fixes, use the forms above under `Bug Fixes`; when everything folded is polish or internal work, place the catch-all under `Polish` as `Make several refinements and internal improvements.` (Chinese: `做了若干细节优化和内部改进。`). - **Merge micro-tweaks to the same surface.** Collapse several small tweaks to the same UI area or feature into one concise entry at the higher level. For example, "change the composer's default height" and "change the composer's default font" merge into "Polish the composer's default styling." Use the most specific common ancestor (composer, settings page, tool card, and so on). Classify the merged entry by its combined effect - **Merge same-surface or same-kind fixes when you have three or more.** The `Bug Fixes` section tends to accumulate many narrow UI/polish fixes that read as noise when listed one by one. When three or more fixes target the same area (for example several tool cards in the TUI, or the web session/conversation surface) or the same class of problem (for example several "jumping/flickering/collapsing during streaming" fixes), merge them into one higher-level entry. Examples: - "Fix the Bash tool card collapsing...", "Fix the Edit tool card jumping in height...", "Fix the Edit tool card flickering while its result streams in" → "Fix several TUI tool cards jumping, flickering, or collapsing in height when results stream in or end with short output." - "Fix the collapsed sidebar not hiding...", "Stop the chat history from replaying its entrance animation...", "Fix tool components jumping the conversation when expanded/collapsed" → "Fix several layout and display glitches when switching sessions, including the collapsed sidebar not hiding, the chat history replaying its entrance animation, and tool components jumping the conversation." - Classify the merged fixes as `Bug Fixes`. - - **Do not over-merge.** Leave a fix standalone when it is broad, high-value, or genuinely distinct (for example model/provider tool-calling bugs, session-list corruption, file-completion gaps). Merging is for low-reader-value, similar-shape fixes that read as a wall of similar bullets. + - **Do not over-merge.** Leave a fix standalone when it is broad, high-value, or genuinely distinct (for example model/provider tool-calling bugs, session-list corruption, file-completion gaps). Merging is for low-reader-value, similar-shape fixes that read as a wall of similar bullets. A merged fix entry must still pass the standalone test from the catch-all rule above; if the merged group is low-signal too, fold it into the catch-all line instead of listing it. - **Drop server/API plumbing covered by a web entry.** If one entry adds a web UI feature (for example, an Archived sessions page) and another entry only adds the server or REST/WebSocket endpoints that exist solely to power that web feature, keep the web UI entry and drop the API entry. CLI and web users perceive the web page; the backing API is implementation detail with no independent user value on this changelog. Keep the API entry only when it has independent user value — a new public endpoint that SDK or server consumers call directly, or a capability usable outside the web feature. When unsure, keep both and let the reviewer decide. The docs changelog uses five section types: @@ -146,6 +154,8 @@ The docs changelog uses five section types: | `### Refactors` | `### 重构` | Internal changes with no user-visible behavior change, including build, CI, tests, dependency cleanup, and internal renames | | `### Other` | `### 其他` | Anything that does not fit above, such as CDN/endpoint swaps and docs-related artifacts | +With the catch-all rule above, `Refactors` and `Other` rarely appear in newly synced versions: entries with no user-perceivable effect fold into the catch-all, and an entry that does change user-perceivable default behavior (for example an engine default flip with an opt-out flag) is classified by that effect, usually `Polish`. Reserve `Other` for genuinely unclassifiable but user-facing entries. Older versions keep whatever sections they already have — do not rewrite history. + Classification process: 1. Classify from the stripped entry text first. @@ -314,6 +324,7 @@ Check: - Each version has the same section set and order on both pages. - Each section has the same number of entries on both pages. - Within each section, the most valuable, obvious, and larger entries appear before smaller or narrower entries. +- Low-signal entries were collapsed into the single catch-all line, placed last under `Bug Fixes` — or under `Polish` when nothing folded is a fix (both the reader-action test and the channel test applied); the catch-all wording matches what was folded and never claims fixes that did not happen; section sizes stay within the density defaults (about 2 Polish, 3 Bug Fixes) unless extra qualifying entries were deliberately kept and flagged for review. The catch-all line ends with the upstream changelog pointer (file link, no version anchor). - PR links and commit hashes were stripped. - No `Thanks ...!` credit remains (remove it every time). - Real internal identifiers were replaced with neutral placeholders. @@ -342,7 +353,7 @@ If the user chooses review: git diff docs/en/release-notes/changelog.md docs/zh/release-notes/changelog.md ``` -2. Summarize synced versions, section counts, and anything that needed manual classification. +2. Summarize synced versions, section counts, and anything that needed manual classification. List every entry folded into a catch-all line (short titles, one line each), any section that exceeds the density defaults, and every borderline call flagged during curation — the reviewer cannot own a cutoff they cannot see. 3. Tell the user to reply when they are done reviewing, or to ask for edits. 4. Do **not** commit, push, or open a PR until the user explicitly says review is complete, or asks to proceed. @@ -435,6 +446,14 @@ Return the PR URL to the user when done. | Leaving the `Thanks ...!` credit in docs | Remove it every time, including the multi-author form | | Leaving near-duplicate micro-tweaks as separate bullets | Merge small tweaks to the same surface into one higher-level entry (e.g. composer height + font → composer's default styling) | | Listing many narrow fixes to the same surface as separate bullets | When three or more fixes target the same UI area or the same class of problem, merge them into one higher-level fix entry; keep genuinely distinct or high-value fixes standalone | +| Listing low-signal fixes or internal changes as standalone bullets | Collapse them into the single catch-all line (`Fix several known issues.`) placed last under Bug Fixes; treat the section-size defaults (about 2 Polish, 3 Bug Fixes) as a density guard, not a quota | +| Folding a qualifying entry just to hit the section-size default | The defaults are density guards; keep entries that genuinely pass the reader-action test and flag the overflow for the human reviewer | +| Keeping a fix because it was severe or hard-won | Severity makes the announcement redundant — the fix itself notifies whoever was hit; keep only behavior-change fixes and retrospective notices with a concrete, locatable action | +| Keeping an improvement the product surfaces in context (recovery cards, post-install guidance, progress displays) | The product is the better channel — right users, moment of need; fold it (channel test) | +| Folding a new capability because its control is visible somewhere in the UI | Visible is not discoverable — users do not explore; a toggle, menu item, or settings page that only waits to be found needs the changelog announcement | +| Keeping a silent-impact fix out of diligence (dropped data, wrong results the user never noticed) | The changelog does not repair the past; if the notice names no locatable instance and no realistic action, it is anxiety without an outlet — fold it | +| Overstating the catch-all pointer (for example claiming the upstream changelog is complete) | Keep the pointer restrained — `See the [changelog on GitHub](...) for more technical entries.`; upstream only contains changes that received a changeset | +| Writing `Fix several known issues.` when nothing folded is a fix | Never claim fixes that did not happen; all-polish/internal folds go under Polish as `Make several refinements and internal improvements.` | | Listing a server/API entry that only backs a web feature already listed | Drop the API entry and keep the web UI entry, unless the API has independent user value | | Rewording upstream English entries | Upstream is frozen; copy the body text unless the user explicitly asks otherwise | | Leaving English text untranslated in the Chinese page | The Chinese page must be fully Chinese except preserved technical terms |