diff --git a/.agents/skills/dsh-pr-description/SKILL.md b/.agents/skills/dsh-pr-description/SKILL.md new file mode 100644 index 0000000000..674aca8b4f --- /dev/null +++ b/.agents/skills/dsh-pr-description/SKILL.md @@ -0,0 +1,168 @@ +--- +name: dsh-pr-description +description: Use when creating a deepseek-harness pull request, or when updating its description after a later push or a handled review round. Defines each description section, Issue references, test design, change-specific disclosures, and the Human and Agent Roles section with its levels, stages, grading rules, and update timing. +user-invocable: false +--- + +# Writing PR descriptions + +This skill defines what a deepseek-harness PR description contains, how to write it, and when to update it. The [PR template](../../../.github/pull_request_template.md) supplies only the section headings and placeholders; this skill owns the requirements for each section. Every PR description follows this skill, including PRs created with `gh pr create --body-file`, which skips the template. + +## Scope + +- Write the complete description when you create the PR. +- After the PR exists, update the affected sections after each later push and after each handled review round. +- Each PR in a stack has its own description, which covers only that layer's changes against its base branch. + +## Description structure + +The description uses four second-level headings, in this order: `## Motivation`, `## Changes`, `## Testing`, and `## Human and Agent Roles`. + +### Motivation + +- State the problem in one sentence. +- Reference at least one same-repository Issue: use `Fixes #N`, `Closes #N`, or `Resolves #N` when the PR resolves it, and `Refs #N` when it only gives context. PR numbers do not count as Issue references, and neither do references inside HTML comments, code fences, or inline code. [Issue management](../../../.github/issue-management/README.md) owns the exact rules and the Priority matching. + +### Changes + +- Interface changes: summarize changes to commands, configuration, APIs, protocols, or persisted formats; write None when there are none. +- Behavior changes: summarize changes that users, models, or the system can observe; write None when there are none. + +### Testing + +Testing starts with the test design, followed by the test entries. + +**Test design**: summarize how the tests cover each item in Changes and why that coverage is complete. Choose the form by change type: + +| Change type | What the test design shows | +|---|---| +| Behavior change | A behavior matrix of scenario × behavior before × behavior after × covering test, showing which scenarios failed or differed before the change | +| Performance change | Before and after values per stage or scenario, with the measurement conditions: machine, run count, and how the value is taken | +| Refactoring or migration without behavior change | How the unchanged behavior is shown: byte-for-byte comparison, unchanged snapshots, or old-versus-new comparison tests | +| Documentation only | How the content is checked: links, bilingual pairing, example compilation, or similar | + +Items that Changes lists as None need no test design. + +**Test entries**: + +- Add one entry per test method; state the command or steps visibly, and the behavior it covers. +- Put reviewable evidence, such as test output, screenshots, recordings, or logs, in that entry's `
Proof` block. + +### Change-specific disclosures + +| Change | What the description states | Rule owner | +|---|---|---| +| Changing the behavior an existing test describes | Why the behavior changed | The Tests describe behavior rule in [root AGENTS.md](../../../AGENTS.md) | +| Raising a ceiling in `scripts/doc-budgets.manifest.json` | Why the words are necessary | [Wordcount budgets](../../../docs/AGENTS.md#wordcount-budgets) | +| Changing product-user-visible GUI behavior | An embedded demonstration GIF, with the demonstrated commit, the serving origin, and whether a real model round ran | [record-browser-gif](../record-browser-gif/SKILL.md#every-gui-pull-request-includes-a-gif) | +| Using a translation term the terminology list lacks | The source of the rendering, or a proposed rendering under pending terms | [Translation rules](../../../docs/i18n/translation-rules.md) | + +## Human and Agent Roles + +This section records who made the decisions in each stage of the PR, and how autonomously the Agent worked. + +### Levels + + + +Levels are ordered from least to most AI involvement; each level pairs an English name with a Chinese name. Autonomy is the Agent's autonomy in that stage, a multiple of 5% within the chosen level's range. + +| Level | Meaning | Agent autonomy | +|---|---|---| +| hint 人工独立 | A human does the work; AI takes no part or only offers passive suggestions that the human accepts or rejects | 0–15% | +| assist 人工主导 | A human supplies the main content or every key decision; AI completes part of the work | 20–40% | +| pair 人工引导 | A human gives the key direction or constraints and revises the AI's output several times; the human understands the internals | 45–60% | +| copilot 人工把关 | AI completes the whole task; a human reviews, selects, or rejects, and decides or clarifies key points without supplying substantive content | 65–85% | +| auto 模型自主 | AI completes the task autonomously; a human only sets the goal or accepts the output | 90–100% | +| n/a 暂不适用 | The stage does not exist or has not happened yet | Omitted | + +### Stages and criteria + + + +Stages appear in a fixed order; each stage pairs an English name with a Chinese name. The criteria below cover assist through auto; judge hint by its meaning in the level table. + +**breakdown 问题拆解**: after the problem appears, whether a human takes part in breaking it down, or the Agent acts on it directly. + +- auto 模型自主: the Agent acts on the problem directly. +- copilot 人工把关: the Agent identifies the subproblems, root cause, and scope; a human confirms or trims them. +- pair 人工引导: a human points to a suspected direction, a key subproblem, or a scope limit, or requires tracing the root cause. +- assist 人工主导: a human supplies the list of subproblems or the root-cause judgment and sets the scope; the Agent works from that breakdown. + +**design 方案设计**: who supplies the logical design, and how many trade-offs and detailed changes the human makes. + +- auto 模型自主: a human adopts the Agent's design as proposed, or only confirms an option the Agent recommends. +- copilot 人工把关: a human chooses among the Agent's designs, or rejects parts of one. +- pair 人工引导: the Agent proposes the design skeleton; a human gives key constraints, names, or several revisions. +- assist 人工主导: a human supplies the design skeleton (module split, data flow, or key interfaces); the Agent fills in the mechanism or writes it up. + +**testing 验收测试**: who sets the acceptance goals, test cases, and test matrix, and who checks the results. For documentation-only changes, the acceptance goals are content requirements. + +- auto 模型自主: the Agent sets the goals and cases, and no human reviews them. +- copilot 人工把关: a human reviews the cases, the test matrix, or the results the Agent reports. +- pair 人工引导: a human sets quantified targets or required scenarios; the Agent designs the concrete cases. +- assist 人工主导: a human defines the goals and the test matrix, and runs or tries the result to check it. + +**implementation 技术实现**: human intervention in the changed content, including production code, documentation (READMEs, JSDoc, Agent Notes, comments), CI, and release scripts. + +- auto 模型自主: the Agent writes every change, and the records show no human diff review. +- copilot 人工把关: a human reviews the diff, including staging it piece by piece, and accepts it or makes a few comments. +- pair 人工引导: a human requires reverting or redoing work, or specifies a refactoring or an implementation approach. +- assist 人工主导: a human writes the key parts; the Agent completes the rest. + +**review 评审处理**: who decides whether each handled review comment is fixed or declined. Comments from bots and from people both count; grade by who decided, not by who posted the reply. + +- auto 模型自主: the Agent decides on and replies to every comment. +- copilot 人工把关: a human gives only a blanket authorization or category-level instructions, or changes only a few items on a handling list the Agent prepared. +- pair 人工引导: a human decides comment by comment whether to fix, decline, or defer every comment other than wording comments, which may be handled by category; the Agent carries out the decisions and replies. +- assist 人工主导: a human replies to reviewers directly, or leads the discussion of disputed items. + +### Grading rules + +- Grade from session records and task records. Messages a human sends in a subagent session count; the instructions an Agent writes to a subagent are not human messages. +- Count only work that ends up in this PR, including work from earlier sessions that ends up in this PR. +- When the records suffice, grade at the level with the most human involvement whose criterion the records meet, and express the human and Agent shares through the autonomy value. Only when the records do not suffice, take the level with less human involvement that the records support. +- When a stage covers several changes, grade by the main change and state how the other changes differ in the description. + +### Line format + +The section starts with one level line, followed by one line per stage in the fixed order: + +```markdown +## Human and Agent Roles + +Levels and Agent autonomy: **hint 人工独立** 0–15%, **assist 人工主导** 20–40%, **pair 人工引导** 45–60%, **copilot 人工把关** 65–85%, **auto 模型自主** 90–100%; **n/a 暂不适用** marks a stage that does not exist or has not happened yet. + +- ** ** · — +``` + +- Write the level in bold and underlined; omit the autonomy value for n/a 暂不适用. +- Write the description in the PR description's language, in one or two sentences of at most 80 Chinese characters or 40 English words. State who made which decisions: name one or two representative decisions, and give only a count for the rest. +- State the description as settled fact, without hedges such as "not seen in the session" or "pending author confirmation". +- Refer to people as the author or a reviewer, never by username. Leave out judgments, session times, session ids, direct quotes, and the running or handling of checks and CI (local skips, hooks, reruns, unrelated failures). + +### Update timing + +- When you create the PR, the review line reads `- **n/a 暂不适用** · review 评审处理 — ` followed by a statement, in the description's language, that no review comments have been handled yet. +- After the PR exists, after each later push and after each handled review round, rewrite the affected lines so that they cover all work so far; do not append a history of changes. +- The review line records only handled review comments; it omits approvals, merge timing, and unhandled comments. + +### Example + + + +Filled in from the session and review records of #6013: + +```markdown +- **pair 人工引导** 45% · breakdown 问题拆解 — The author identified two process-specific values that do not belong in the system prompt and pointed to the custom model route; the Agent traced the root cause. +- **assist 人工主导** 25% · design 方案设计 — The author supplied the skeleton: runtime context, frozen legacy sections for old sessions, and a separate package; the Agent filled in the projection matching. +- **pair 人工引导** 50% · testing 验收测试 — The author required two scenarios: restoring an old session after upgrade, and changing ports after upgrade; the Agent wrote the cases and snapshots. +- **pair 人工引导** 45% · implementation 技术实现 — The Agent wrote the code and the Agent Note; the author required one revert and specified 3 approaches, such as getOrigin() instead of an origin property. +- **pair 人工引导** 50% · review 评审处理 — The author decided each bot comment, such as no upgrade guide and keeping a devDependency; the Agent fixed and replied. +``` + +## Creating and updating the description + +1. Write the description to a file that git ignores, such as `.artifacts/pr/body.md`. Create the PR with `gh pr create --body-file `, or update it with `gh pr edit --body-file `; when the description embeds a GIF, follow [record-browser-gif](../record-browser-gif/SKILL.md) and use `--attach`. +2. Before an update, save the current description with `gh pr view --json body --jq .body`, and change only the sections that need it: keep content and media the author wrote, and remove statements that no longer match the code. +3. After writing, read the description back and confirm that all four sections are present and that Human and Agent Roles matches the current code and review state. diff --git a/.agents/skills/pr-declare/SKILL.md b/.agents/skills/pr-declare/SKILL.md deleted file mode 100644 index ddd164b5e7..0000000000 --- a/.agents/skills/pr-declare/SKILL.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -name: pr-declare -description: Use when the user asks to declare AI usage in a pull/merge request. Adds or updates an AI-usage declaration block (badge + level, optionally per-process) inside a GitHub or GitLab PR/MR description, following the DimwitLabs AI-DECLARATION.md spec. ---- - -# PR Declaration - -Add an AI-usage declaration to a **pull/merge request description** following the [DimwitLabs AI-DECLARATION.md](https://ai-declaration.md) specification. Unlike a repo-level `AI-DECLARATION.md`, this declares how much AI was involved in producing *this specific PR*, and lives in the PR body. - -## When to Use - -Explicit skill invocation, in agents that expose skills as slash commands: -- `/pr-declare` — asks the user for a level, then adds/updates the PR declaration -- `/pr-declare ` — uses the specified level directly - -Also use this when the user asks to "declare AI usage on this PR", "add an AI declaration to the MR", or similar. - -Works with GitHub (`gh`) and GitLab (`glab`). - -## Spec Fidelity - -The spec evolves. Do **not** rephrase or paraphrase any text taken from the spec — version strings, level names, level definitions, process names, and badge URLs must be reproduced verbatim. Treat the upstream spec as the single source of truth. - -## Process - -### Step 0: Fetch the current spec - -Before prompting, fetch the live spec so the skill stays in sync with upstream: - -1. Fetch `https://raw.githubusercontent.com/DimwitLabs/AI-DECLARATION.md/main/package.json` and read the `version` field — the **current spec version**. -2. Fetch `https://raw.githubusercontent.com/DimwitLabs/AI-DECLARATION.md/main/README.md` and extract three bullet lists verbatim: the **level definitions** under the `Levels` heading, the **process definitions** under the `Processes` heading, and the **badge** for each level under the `Badges` heading. Match each heading by its text at any heading depth. - -Use the fetched values only when `version` matches `^\d+\.\d+\.\d+$`, the level and process lists are non-empty, and every level has a badge. If a fetch fails (offline, rate-limited) or this check fails, use the frozen fallback below and tell the user the skill is using it. - -**Frozen fallback (spec `0.1.2`):** - -Levels: - -- `none`: Human acts on the task alone with no AI involvement. -- `hint`: Human acts on the task and the AI surfaces suggestions passively. -- `assist`: Human prompts and the AI acts on a part of the task. -- `pair`: Human prompts as both human and AI both act on the task equally; Human understands internals clearly. -- `copilot`: Human prompts and AI acts on the whole task, prompting the Human for permission or clarification. -- `auto`: Human prompts and AI acts autonomously bringing the task to completion. - -Processes: - -- `design`: Architecture, system design, and decision-making. -- `implementation`: Writing production code. -- `testing`: Writing tests, test plans, and quality assurance. -- `documentation`: Writing docs, comments, READMEs, and changelogs. -- `review`: Code review and pull request feedback. -- `deployment`: CI/CD configuration, infrastructure, and release scripts. - -Badges: - -- [![AI-DECLARATION: none](https://img.shields.io/badge/䷼%20AI--DECLARATION-none-dcfce7?labelColor=dcfce7)](https://ai-declaration.md) -- [![AI-DECLARATION: hint](https://img.shields.io/badge/䷼%20AI--DECLARATION-hint-ecfccb?labelColor=ecfccb)](https://ai-declaration.md) -- [![AI-DECLARATION: assist](https://img.shields.io/badge/䷼%20AI--DECLARATION-assist-fef9c3?labelColor=fef9c3)](https://ai-declaration.md) -- [![AI-DECLARATION: pair](https://img.shields.io/badge/䷼%20AI--DECLARATION-pair-ffedd5?labelColor=ffedd5)](https://ai-declaration.md) -- [![AI-DECLARATION: copilot](https://img.shields.io/badge/䷼%20AI--DECLARATION-copilot-fee2e2?labelColor=fee2e2)](https://ai-declaration.md) -- [![AI-DECLARATION: auto](https://img.shields.io/badge/䷼%20AI--DECLARATION-auto-ede9fe?labelColor=ede9fe)](https://ai-declaration.md) - -Use the fetched (or fallback) values in every subsequent step. The levels are ordered from least to most AI involvement in the order the spec lists them. - -### Step 1: Identify the PR/MR - -Determine which PR to annotate: the PR/MR URL or number the user gave, otherwise the PR/MR for the current branch. If no PR exists yet, ask whether to create a draft one or wait. Do not push or open a PR without user approval. - -Detect the forge from the URL or the git remote host (`github.com` → `gh`, a GitLab host → `glab`). Record the PR/MR **target**: the full URL on GitHub, or the MR number plus `-R ` on GitLab, so a URL from another repository never resolves against the current checkout. For the current branch, read the URL from `gh pr view --json url` or `web_url` from `glab mr view -F json`. - -### Step 2: Determine the level - -If the user provided a level with the command, validate it against the level names from Step 0. If invalid, tell the user and list valid options. A valid level is the single global level: skip Step 3. - -If **no level was specified**, ask the user to select one, presenting the level bullets **verbatim** as fetched in Step 0: - -> Which AI involvement level best describes this PR? -> -> (one bullet per level from Step 0, unchanged) - -Wait for the user to respond before proceeding. - -### Step 3: Determine the scope - -Ask whether to declare **per-process** levels or just a single global level: - -> Would you like to declare per-process levels (design, implementation, testing, etc.) or just a single global level? -> 1. **Global only** — One level for the whole PR -> 2. **Per-process** — Different levels for different phases - -If per-process, ask for a level for every process from Step 0. - -The global level shown in the badge must be the **highest** level among declared processes, using the level order from Step 0. Any process not listed is implicitly `none`. - -### Step 4: Build the declaration block - -Assemble a self-contained markdown block delimited by HTML comment markers so it can be found and updated idempotently: - -```markdown - -> - -**AI declaration** ([v](https://ai-declaration.md/en/)): `` - -``` - -For per-process declarations, append a list before the end marker: - -```markdown - -> - -**AI declaration** ([v](https://ai-declaration.md/en/)): `` - -- design: `` -- implementation: `` - -``` - -Replace `` with the Step 0 badge for the global (highest) level, without the leading `- `. - -### Step 5: Update the PR description - -After all user interaction is complete, fetch the current body so edits made while waiting are kept: -- GitHub: `gh pr view --json number,url,body` (read `body`) -- GitLab: `glab mr view -F json` (read `iid`, `web_url`, and `description`) - -Then: -- If a block between `` and `` already exists, **replace** it in place (keep its position). -- Otherwise, **append** the block at the end of the body (after a blank line). - -Never drop or reorder the user's existing description text. - -Write the updated body back: -- GitHub: `gh pr edit --body-file ` -- GitLab: `glab mr update --description "$(cat )"` - -Write the body to a temp file first so the markdown is never shell-escaped; `gh` reads the file and `glab` receives its contents through `$(cat …)`. - -### Step 6: Confirm - -Summarize: -- The PR/MR that was updated (number + URL) -- The declared level (and per-process levels, if any) -- That the declaration block was inserted or replaced - -## Common Mistakes - -- **Mentioning a username**: Never include a username in the declaration. diff --git a/.github/issue-management/policy.test.mjs b/.github/issue-management/policy.test.mjs index 91939c029a..c0161ece04 100644 --- a/.github/issue-management/policy.test.mjs +++ b/.github/issue-management/policy.test.mjs @@ -206,19 +206,32 @@ test('keeps Task Issues limited to summary and deliverables', () => { ) }) -test('structures the pull request template around motivation, changes, and testing', () => { +test('keeps the pull request template as the skeleton of the dsh-pr-description skill', () => { const source = readFileSync(new URL('../pull_request_template.md', import.meta.url), 'utf8') - for (const heading of ['## Motivation', '## Changes', '## Testing']) { - assert.match(source, new RegExp(`^${heading.replaceAll('#', '\\#')}$`, 'm')) - } + const skillPath = '.agents/skills/dsh-pr-description/SKILL.md' + const skill = readFileSync(new URL(`../../${skillPath}`, import.meta.url), 'utf8') + assert.ok(source.startsWith(`\n`), 'the template points to the skill') + assert.deepEqual(source.match(/^## .+$/gm), [ + '## Motivation', + '## Changes', + '## Testing', + '## Human and Agent Roles', + ]) assert.doesNotMatch(source, /^### /m) - assert.match( - source, - /\n/, - ) assert.match(source, /- \n\n
\n Proof<\/summary>/) assert.equal(source.match(/
/g)?.length, 1) assert.equal(source.match(/<\/details>/g)?.length, 1) + + const levelLine = /^Levels and Agent autonomy: .+$/m + assert.ok(skill.match(levelLine), 'the skill shows the role level line') + assert.equal(source.match(levelLine)?.[0], skill.match(levelLine)?.[0], 'the template level line matches the skill') + const skillStages = [...skill.matchAll(/^\*\*([a-z]+ \S+)\*\*:/gm)].map(([, stage]) => stage) + assert.ok(skillStages.length > 0, 'the skill lists role stages') + assert.deepEqual( + [...source.matchAll(/^- \*\*待填级别\*\*<\/ins> \?% · (.+?) — 待填说明$/gm)].map(([, stage]) => stage), + skillStages, + 'the template has one placeholder line per skill stage, in skill order', + ) }) test('ignores Issue title, body presentation, and assignee ownership', () => { diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 7b475e71f5..caa92c120d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,21 +1,26 @@ -## Motivation + - +## Motivation ## Changes - - - ## Testing - + -- +-
Proof - -
+ +## Human and Agent Roles + +Levels and Agent autonomy: **hint 人工独立** 0–15%, **assist 人工主导** 20–40%, **pair 人工引导** 45–60%, **copilot 人工把关** 65–85%, **auto 模型自主** 90–100%; **n/a 暂不适用** marks a stage that does not exist or has not happened yet. + +- **待填级别** ?% · breakdown 问题拆解 — 待填说明 +- **待填级别** ?% · design 方案设计 — 待填说明 +- **待填级别** ?% · testing 验收测试 — 待填说明 +- **待填级别** ?% · implementation 技术实现 — 待填说明 +- **待填级别** ?% · review 评审处理 — 待填说明 diff --git a/AGENTS.md b/AGENTS.md index 5e2108e151..5963565627 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -161,6 +161,7 @@ Real-API tests/demos read `DEEPSEEK_API_KEY`, optional `DEEPSEEK_BASE_URL`, and - **Both SDKs project the loop.** Agent-loop, session-lifecycle, and `SessionEventMap` changes update the TypeScript and Python SDK expected outputs in the same PR; `pnpm run test` covers neither ([surfaces](docs/testing.md#when-a-snapshot-test-is-required)). - **Choose PR history deliberately.** Split independent changes and fix the introducing PR before propagation. Standalone/stack branches may merge-forward or rebase. Rewrites use `--force-with-lease`, abort on remote movement, never raw `--force`; preserve an in-progress merge-forward checkpoint before taking a newer base ([rationale](.agents/notes/implemented/process/2026-08-02-native-github-stacks-and-optional-rebases.md)). - **Labels:** one PR `kind/*`, all material `area/*`, and native Issue Type ([taxonomy](.agents/notes/implemented/process/2026-08-08-unified-github-label-taxonomy.md)). +- **PR descriptions:** write every PR description with [dsh-pr-description](.agents/skills/dsh-pr-description/SKILL.md), including PRs created with `gh pr create --body-file`, and update it after each later push or handled review round. - TODO markers: `FIXME`/`TODO`/`XXX` by urgency ([semantics](docs/development.md)). - Files end with exactly one trailing newline; `git diff --cached --check` (pre-commit) gates it.