diff --git a/.agents/skills/dsh-pr-description/SKILL.md b/.agents/skills/dsh-pr-description/SKILL.md index b893c6bf0f..5841e73f94 100644 --- a/.agents/skills/dsh-pr-description/SKILL.md +++ b/.agents/skills/dsh-pr-description/SKILL.md @@ -18,7 +18,7 @@ This skill defines what a deepseek-harness PR description contains, how to write The description uses four second-level headings, in this order: `## Motivation`, `## Changes`, `## Testing`, and `## AI Usage`. -Write all headings and labels, such as **Interface changes**, **Behavior changes**, **Test design**, and **Test entries**, in English. Write the rest of the description in Chinese unless a human asked for another language for this PR. +Write fixed section headings and labels, such as **Interface changes**, **Behavior changes**, **Test design**, and **Test entries**, in English. Write table headers and the rest of the description in the PR description's language, Chinese unless a human asked for another language. ### Motivation @@ -131,7 +131,7 @@ Stages appear in a fixed order; each stage pairs an English name with a Chinese ### Badge URLs -The AI-DECLARATION block pins specification version 0.1.2. Use the badge for the highest level among the stage rows; a stage with n/a 暂不适用 does not affect the highest level. +The AI-DECLARATION block pins specification version 0.1.2. Use the badge URL for the level selected in [Section format](#section-format); the badges follow [AI-DECLARATION](https://ai-declaration.md). | Level | Badge URL | |---|---| @@ -141,7 +141,7 @@ The AI-DECLARATION block pins specification version 0.1.2. Use the badge for the | copilot 人工把关 | `https://img.shields.io/badge/䷼%20AI--DECLARATION-copilot-fee2e2?labelColor=fee2e2` | | auto 模型自主 | `https://img.shields.io/badge/䷼%20AI--DECLARATION-auto-ede9fe?labelColor=ede9fe` | -When the upstream specification changes, update this version and the version link in the declaration block together. +When the upstream specification changes, update every version reference in this skill and the PR template. ### Section format @@ -161,10 +161,9 @@ The section starts with the AI-DECLARATION block, followed by one table row per | | | | | ``` -- The badge level is the highest level among the stage rows; ignore rows with n/a 暂不适用. +- The badge level is the level with the most AI involvement among the stage rows; ignore rows with n/a 暂不适用. This follows the [specification's rule](https://ai-declaration.md) that the global level is the highest declared level. - Keep the `ai-declaration` markers so an existing declaration can be replaced in place without duplicating it. - 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. -- Write `—` for the AI involvement of a stage with n/a 暂不适用. - 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). @@ -201,5 +200,5 @@ Filled in from the session and review records of #6013: ## 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, replace only the contents of an existing `ai-declaration` block, 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 AI Usage matches the current code and review state. +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, replace only the contents of an existing `ai-declaration` block, and remove statements that no longer match the code. When the description still has the old `## Human and Agent Roles` heading, replace that heading and its level line with `## AI Usage` and the block; keep only one AI Usage section. +3. After writing, read the description back and confirm that all four sections are present, that AI Usage matches the current code and review state, and that no old `## Human and Agent Roles` section remains. diff --git a/.github/issue-management/policy.test.mjs b/.github/issue-management/policy.test.mjs index e1242e66a0..18b7114d45 100644 --- a/.github/issue-management/policy.test.mjs +++ b/.github/issue-management/policy.test.mjs @@ -218,10 +218,6 @@ test('keeps the pull request template aligned with the dsh-pr-description skill' '## AI Usage', ]) assert.doesNotMatch(source, /^### /m) - assert.doesNotMatch(source, //) - const usageSection = source.slice(source.indexOf('## AI Usage')) - assert.ok(usageSection.includes(''), 'the AI declaration block is in AI Usage') - assert.ok(usageSection.includes('| 阶段 | 级别 | AI 参与度 | 决策记录 |'), 'the role table is in AI Usage') assert.match(source, /^## Motivation\n\n$/m, 'the template prompts for an Issue reference') assert.match(source, /- \n\n
\n Proof<\/summary>/) assert.equal(source.match(/
/g)?.length, 1) @@ -230,7 +226,7 @@ test('keeps the pull request template aligned with the dsh-pr-description skill' const stagesSection = skill.match(/^### Stages and criteria\n([\s\S]*?)(?=^### )/m)?.[1] assert.ok(stagesSection, 'the skill has a Stages and criteria section') const skillStages = [...stagesSection.matchAll(/^\*\*(.+?)\*\*:/gm)].map(([, stage]) => stage) - assert.ok(skillStages.length > 0, 'the skill lists role stages') + assert.ok(skillStages.length > 0, 'the skill lists stages') for (const stage of skillStages) { assert.match(stage, /^[a-z]+ [\u4e00-\u9fff]+$/, `stage name pairs one English word with a Chinese name: ${stage}`) } @@ -255,7 +251,11 @@ test('keeps the pull request template aligned with the dsh-pr-description skill' `the skill has the ${level} badge URL`, ) } - assert.ok(skill.includes('[v0.1.2](https://ai-declaration.md/en/0.1.2)'), 'the skill pins the specification version') + const specVersion = skill.match(/pins specification version (\d+\.\d+\.\d+)/)?.[1] + assert.ok(specVersion, 'the skill pins the specification version') + const versionLink = `[v${specVersion}](https://ai-declaration.md/en/${specVersion})` + assert.ok(skill.includes(versionLink), 'the skill links the pinned specification version') + assert.ok(source.includes(versionLink), 'the template links the pinned specification version') const sectionFormat = skill.match(/^### Section format\n[\s\S]*?```markdown\n([\s\S]*?)```/m)?.[1] assert.ok(sectionFormat, 'the skill shows the section format') @@ -268,7 +268,8 @@ test('keeps the pull request template aligned with the dsh-pr-description skill' assert.match(markdown, /^## AI Usage$/m, `the ${label} uses the AI Usage heading`) assert.match(markdown, /^$/m, `the ${label} starts the declaration block`) assert.match(markdown, /^$/m, `the ${label} ends the declaration block`) - assert.ok(markdown.includes('| 阶段 | 级别 | AI 参与度 | 决策记录 |'), `the ${label} shows the role table header`) + assert.ok(markdown.includes('| 阶段 | 级别 | AI 参与度 | 决策记录 |'), `the ${label} shows the stage table header`) + assert.ok(markdown.includes(versionLink), `the ${label} uses the pinned specification version`) } const exampleRows = [...example.matchAll(/^\| .+? \| ([a-z]+) [^|]+ \| (\d+)% \| .+$/gm)] assert.ok(exampleRows.length > 0, 'the example has stage rows') @@ -282,18 +283,20 @@ test('keeps the pull request template aligned with the dsh-pr-description skill' assert.ok(declarationBlock, 'the template has one ordered AI declaration block') assert.equal(source.match(//g)?.length, 1) assert.equal(source.match(//g)?.length, 1) - assert.match( - declarationBlock, - /^\[!\[AI-DECLARATION: 待填级别\]\(https:\/\/img\.shields\.io\/badge\/[^)]+\)\]\(https:\/\/ai-declaration\.md\)$/m, - 'the block has the badge link', + assert.ok( + declarationBlock.includes( + '[![AI-DECLARATION: 待填级别](https://img.shields.io/badge/䷼%20AI--DECLARATION-待填级别-e5e7eb?labelColor=e5e7eb)](https://ai-declaration.md)', + ), + 'the block has the placeholder badge link', ) - assert.match( - declarationBlock, - /^\*\*AI declaration\*\* \(\[v0\.1\.2\]\(https:\/\/ai-declaration\.md\/en\/0\.1\.2\)\): `待填级别`$/m, + assert.ok( + declarationBlock.includes(`**AI declaration** (${versionLink}): \`待填级别\``), 'the block pins the declaration', ) - assert.ok(source.includes('| 阶段 | 级别 | AI 参与度 | 决策记录 |'), 'the template has the role table header') + const usageSection = source.slice(source.indexOf('## AI Usage')) + assert.ok(usageSection.includes(''), 'the AI declaration block is in AI Usage') + assert.ok(usageSection.includes('| 阶段 | 级别 | AI 参与度 | 决策记录 |'), 'the stage table is in AI Usage') assert.ok(source.includes('|:--|:--|--:|:--|'), 'the template right-aligns AI involvement') assert.deepEqual( [...source.matchAll(/^\| (.+?) \| (?:待填级别|n\/a 暂不适用) \| (?:\?%|—) \| .+$/gm)].map(([, stage]) => stage), @@ -311,8 +314,8 @@ test('keeps the pull request template aligned with the dsh-pr-description skill' ['template', source], ['skill', skill], ]) { - assert.doesNotMatch(text, /Human and Agent Roles/, `${label} has no old heading`) - assert.doesNotMatch(text, /autonomy/i, `${label} has no old autonomy term`) + assert.doesNotMatch(text, /^## Human and Agent Roles$/m, `${label} has no old heading`) + assert.doesNotMatch(text, /^Levels and Agent autonomy:/m, `${label} has no old level line`) assert.doesNotMatch(text, //, `${label} has no old underline markup`) } }) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4a735e6a50..3579e77136 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -20,7 +20,7 @@ ## AI Usage -[![AI-DECLARATION: 待填级别](https://img.shields.io/badge/䷼%20AI--DECLARATION-待填级别-lightgrey)](https://ai-declaration.md) +[![AI-DECLARATION: 待填级别](https://img.shields.io/badge/䷼%20AI--DECLARATION-待填级别-e5e7eb?labelColor=e5e7eb)](https://ai-declaration.md) **AI declaration** ([v0.1.2](https://ai-declaration.md/en/0.1.2)): `待填级别`