fix(#3303): correct code_review_depth doc; add agent_skills array form (#3449)

* fix(#3303): correct code_review_depth doc; add agent_skills array form

* fix(#3303): backfill changeset pr field

---------

Co-authored-by: sim <sim@local>
This commit is contained in:
Tom Boucher
2026-08-14 02:39:17 -04:00
committed by GitHub
parent f78a4b3b80
commit 8fba67a674
3 changed files with 83 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3449
---
planning-config.md documented "light" as an allowed workflow.code_review_depth value, but config-set only accepts quick/standard/deep — the reference now matches the validator, pinned by a doc↔capability-registry parity test. The agent_skills row now also documents the array-of-strings form for assigning multiple skill sets to one agent type.

View File

@@ -275,7 +275,7 @@ Set via `workflow.*` namespace in config.json (e.g., `"workflow": { "research":
| `workflow.code_review_command` | string\|null | `null` | Any shell command | External code-review command integrated into `/gsd:ship`. The diff is piped to the command via stdin; the command must output JSON with a `verdict` field (`"APPROVED"` or `"REVISE"`). Non-zero exit or `"REVISE"` verdict blocks the ship workflow. When unset, the built-in review flow runs. Example: `my-review-tool --review`. | | `workflow.code_review_command` | string\|null | `null` | Any shell command | External code-review command integrated into `/gsd:ship`. The diff is piped to the command via stdin; the command must output JSON with a `verdict` field (`"APPROVED"` or `"REVISE"`). Non-zero exit or `"REVISE"` verdict blocks the ship workflow. When unset, the built-in review flow runs. Example: `my-review-tool --review`. |
| `workflow.inline_plan_threshold` | number | `2` | `0`–`10` | Plans with ≤N tasks execute inline instead of spawning a subagent | | `workflow.inline_plan_threshold` | number | `2` | `0`–`10` | Plans with ≤N tasks execute inline instead of spawning a subagent |
| `workflow.code_review` | boolean | `true` | `true`, `false` | Enable built-in code review step in the ship workflow | | `workflow.code_review` | boolean | `true` | `true`, `false` | Enable built-in code review step in the ship workflow |
| `workflow.code_review_depth` | string | `"standard"` | `"light"`, `"standard"`, `"deep"` | Depth level for code review analysis in the ship workflow | | `workflow.code_review_depth` | string | `"standard"` | `"quick"`, `"standard"`, `"deep"` | Depth level for code review analysis in the ship workflow |
| `workflow._auto_chain_active` | boolean | `false` | `true`, `false` | Internal: tracks whether autonomous chaining is active | | `workflow._auto_chain_active` | boolean | `false` | `true`, `false` | Internal: tracks whether autonomous chaining is active |
| `workflow.security_enforcement` | boolean | `true` | `true`, `false` | Enable threat-model-anchored security verification via `/gsd:secure-phase`. When `false`, security checks are skipped entirely | | `workflow.security_enforcement` | boolean | `true` | `true`, `false` | Enable threat-model-anchored security verification via `/gsd:secure-phase`. When `false`, security checks are skipped entirely |
| `workflow.security_asvs_level` | number | `1` | `1`, `2`, `3` | OWASP ASVS verification level. Level 1 = opportunistic, Level 2 = standard, Level 3 = comprehensive. Scales both planner threat-disposition rigor (which threats must be mitigated vs. accepted) and auditor verification depth (grep-level → boundary-placement check → full data-flow trace). See `gsd-core/references/security-asvs-levels.md`. | | `workflow.security_asvs_level` | number | `1` | `1`, `2`, `3` | OWASP ASVS verification level. Level 1 = opportunistic, Level 2 = standard, Level 3 = comprehensive. Scales both planner threat-disposition rigor (which threats must be mitigated vs. accepted) and auditor verification depth (grep-level → boundary-placement check → full data-flow trace). See `gsd-core/references/security-asvs-levels.md`. |
@@ -362,7 +362,7 @@ Set via `manager.*` namespace (e.g., `"manager": { "flags": { "discuss": "--auto
|-----|------|---------|----------------|-------------| |-----|------|---------|----------------|-------------|
| `parallelization` | boolean\|object | `true` | `true`, `false`, `{ "enabled": true }` | Enable parallel wave execution; object form allows additional sub-keys | | `parallelization` | boolean\|object | `true` | `true`, `false`, `{ "enabled": true }` | Enable parallel wave execution; object form allows additional sub-keys |
| `model_overrides` | object\|null | `null` | `{ "<agent-type>": "<model-id>" }` | Override model selection per agent type | | `model_overrides` | object\|null | `null` | `{ "<agent-type>": "<model-id>" }` | Override model selection per agent type |
| `agent_skills` | object | `{}` | `{ "<agent-type>": "<skill-set>" }` | Assign skill sets to specific agent types | | `agent_skills` | object | `{}` | `{ "<agent-type>": "<skill-set>" }` or `{ "<agent-type>": ["<skill-set>", "<skill-set>", ...] }` | Assign skill sets to specific agent types. Each value is a single skill-set path (string) or an array of skill-set paths — the array form assigns multiple skill sets to one agent type. Paths cannot be comma-joined into one string; each path must be its own array element |
| `sub_repos` | array | `[]` | Array of relative path strings | Child directories with independent `.git` repos (auto-detected) | | `sub_repos` | array | `[]` | Array of relative path strings | Child directories with independent `.git` repos (auto-detected) |
### Planning Fields ### Planning Fields

View File

@@ -238,6 +238,82 @@ describe('config-field-docs', () => {
}); });
}); });
// ─── Capability-enum doc parity (#3303) ─────────────────────────────────────
describe('capability-enum doc parity (#3303)', () => {
const CAPABILITY_PATH = path.join(
__dirname, '..', 'capabilities', 'code-review', 'capability.json'
);
let docContent;
let capability;
before(() => {
docContent = fs.readFileSync(REFERENCE_PATH, 'utf-8');
capability = JSON.parse(fs.readFileSync(CAPABILITY_PATH, 'utf-8'));
});
/**
* Extract a single Complete-Field-Reference table row by key and split it into
* trimmed cells: ['', '`key`', type, default, allowedValues, description, ''].
* Row-scoping keeps unrelated wording elsewhere in the doc from satisfying
* (or breaking) the parity assertions.
*/
function docRow(key) {
const line = docContent
.split(/\r?\n/)
.find(l => l.startsWith(`| \`${key}\` |`));
assert.ok(line, `planning-config.md must have a table row for \`${key}\``);
return line.split('|').map(c => c.trim());
}
test('workflow.code_review_depth allowed values match the capability registry (#3303)', () => {
const spec = capability.config && capability.config['workflow.code_review_depth'];
assert.ok(
spec && Array.isArray(spec.values),
'capabilities/code-review/capability.json must declare workflow.code_review_depth values'
);
const allowedCell = docRow('workflow.code_review_depth')[4];
const docValues = [...allowedCell.matchAll(/"([^"]+)"/g)].map(m => m[1]);
assert.ok(
docValues.length > 0,
`workflow.code_review_depth Allowed-Values cell must list quoted values, got: ${allowedCell}`
);
assert.deepStrictEqual(
[...docValues].sort(),
[...spec.values].sort(),
`planning-config.md workflow.code_review_depth allowed values (${docValues.join(', ')}) ` +
`must exactly match what config-set accepts per capability.json (${spec.values.join(', ')})`
);
});
test('workflow.code_review_depth default matches the capability registry (#3303)', () => {
const spec = capability.config && capability.config['workflow.code_review_depth'];
assert.ok(spec, 'capability.json must declare workflow.code_review_depth');
const defaultCell = docRow('workflow.code_review_depth')[3];
const [docDefault] = [...defaultCell.matchAll(/"([^"]+)"/g)].map(m => m[1]);
assert.strictEqual(
docDefault,
spec.default,
`planning-config.md workflow.code_review_depth default must match capability.json default (${spec.default})`
);
});
test('agent_skills row documents the array-of-strings form (#3303)', () => {
const cells = docRow('agent_skills');
const allowedCell = cells[4];
assert.ok(
/\[\s*"<skill-set>"\s*,/.test(allowedCell),
`agent_skills Allowed-Values cell must show the array-of-strings form, got: ${allowedCell}`
);
assert.ok(
/array/i.test(cells[5]),
'agent_skills description must explain the array form assigns multiple skill sets to one agent type'
);
});
});
// ─── CONFIGURATION.md parity (#1216) ──────────────────────────────────────── // ─── CONFIGURATION.md parity (#1216) ────────────────────────────────────────
describe('CONFIGURATION.md parity (#1216)', () => { describe('CONFIGURATION.md parity (#1216)', () => {