vouchington-tooling 0.22.1 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +102 -4
  2. package/dist/agent-blackboard/client.d.mts +34 -0
  3. package/dist/agent-blackboard/client.mjs +41 -0
  4. package/dist/agent-blackboard/feedback-canonical.d.mts +1 -0
  5. package/dist/agent-blackboard/feedback-canonical.mjs +13 -0
  6. package/dist/agent-blackboard/feedback-codec.d.mts +7 -0
  7. package/dist/agent-blackboard/feedback-codec.mjs +121 -0
  8. package/dist/agent-blackboard/feedback-compose.d.mts +37 -0
  9. package/dist/agent-blackboard/feedback-compose.mjs +109 -0
  10. package/dist/agent-blackboard/feedback-deadline.d.mts +1 -0
  11. package/dist/agent-blackboard/feedback-deadline.mjs +18 -0
  12. package/dist/agent-blackboard/feedback-delivery.d.mts +18 -0
  13. package/dist/agent-blackboard/feedback-delivery.mjs +88 -0
  14. package/dist/agent-blackboard/feedback-fields.d.mts +4 -0
  15. package/dist/agent-blackboard/feedback-fields.mjs +38 -0
  16. package/dist/agent-blackboard/feedback-identity.d.mts +2 -0
  17. package/dist/agent-blackboard/feedback-identity.mjs +29 -0
  18. package/dist/agent-blackboard/feedback-online-error.d.mts +7 -0
  19. package/dist/agent-blackboard/feedback-online-error.mjs +23 -0
  20. package/dist/agent-blackboard/feedback-online.d.mts +2 -0
  21. package/dist/agent-blackboard/feedback-online.mjs +137 -0
  22. package/dist/agent-blackboard/feedback-outbox.d.mts +8 -0
  23. package/dist/agent-blackboard/feedback-outbox.mjs +157 -0
  24. package/dist/agent-blackboard/feedback-types.d.mts +66 -0
  25. package/dist/agent-blackboard/feedback-types.mjs +1 -0
  26. package/dist/agent-blackboard/index.d.mts +16 -39
  27. package/dist/agent-blackboard/index.mjs +35 -81
  28. package/dist/cli/commands/agent-blackboard.mjs +35 -4
  29. package/dist/cli/usage.d.mts +1 -1
  30. package/dist/cli/usage.mjs +3 -1
  31. package/dist/markdown/details-scope.d.mts +13 -0
  32. package/dist/markdown/details-scope.mjs +73 -0
  33. package/dist/markdown/document-sections.d.mts +3 -0
  34. package/dist/markdown/document-sections.mjs +64 -0
  35. package/dist/markdown/document-types.d.mts +21 -0
  36. package/dist/markdown/document-types.mjs +1 -0
  37. package/dist/markdown/index.d.mts +3 -0
  38. package/dist/markdown/index.mjs +2 -0
  39. package/dist/markdown/validate-sections.d.mts +3 -0
  40. package/dist/markdown/validate-sections.mjs +34 -0
  41. package/dist/retrospective-facts/coverage.d.mts +6 -0
  42. package/dist/retrospective-facts/coverage.mjs +42 -0
  43. package/dist/retrospective-facts/index.d.mts +3 -0
  44. package/dist/retrospective-facts/index.mjs +18 -1
  45. package/dist/retrospective-transcript/codex.mjs +8 -3
  46. package/dist/retrospective-transcript/index.d.mts +5 -0
  47. package/dist/retrospective-transcript/index.mjs +29 -9
  48. package/dist/session-friction/classify.mjs +25 -14
  49. package/dist/session-friction/coverage-ledger.d.mts +10 -0
  50. package/dist/session-friction/coverage-ledger.mjs +75 -0
  51. package/dist/session-friction/index.d.mts +1 -1
  52. package/dist/session-friction/log-file.d.mts +2 -2
  53. package/dist/session-friction/log-file.mjs +22 -10
  54. package/dist/session-friction/log.mjs +57 -10
  55. package/dist/session-friction/report.mjs +36 -7
  56. package/dist/session-friction/sandbox.mjs +11 -4
  57. package/dist/session-friction/types.d.mts +25 -4
  58. package/dist/workflow-policy/index.d.mts +1 -1
  59. package/dist/workflow-policy/index.mjs +1 -1
  60. package/dist/workflow-policy/permission-declarations.d.mts +14 -0
  61. package/dist/workflow-policy/permission-declarations.mjs +55 -0
  62. package/dist/workflow-policy/permission-inheritance.d.mts +8 -0
  63. package/dist/workflow-policy/permission-inheritance.mjs +88 -0
  64. package/dist/workflow-policy/permission-mismatches.d.mts +4 -1
  65. package/dist/workflow-policy/permission-mismatches.mjs +14 -3
  66. package/docs/workflow-and-compiler.md +18 -1
  67. package/package.json +1 -1
  68. package/skills/agent-workflow/SKILL.md +5 -0
  69. package/skills/agent-workflow/references/review.md +3 -0
  70. package/skills/blackboard/SKILL.md +34 -14
  71. package/skills/manifest.json +21 -21
  72. package/skills/pr-description/SKILL.md +44 -10
  73. package/skills/pr-description/references/examples.md +136 -0
  74. package/skills/retrospective/SKILL.md +27 -16
  75. package/skills/retrospective-distill/SKILL.md +15 -6
  76. package/skills/review-ci-logs/SKILL.md +10 -0
@@ -0,0 +1,55 @@
1
+ export const PERMISSION_LEVEL_RANK = { none: 0, read: 1, write: 2 };
2
+ const LEVELS_BY_SCOPE = {
3
+ actions: ['none', 'read', 'write'],
4
+ 'artifact-metadata': ['none', 'read', 'write'],
5
+ attestations: ['none', 'read', 'write'],
6
+ checks: ['none', 'read', 'write'],
7
+ 'code-quality': ['none', 'read', 'write'],
8
+ contents: ['none', 'read', 'write'],
9
+ deployments: ['none', 'read', 'write'],
10
+ discussions: ['none', 'read', 'write'],
11
+ 'id-token': ['none', 'write'],
12
+ issues: ['none', 'read', 'write'],
13
+ models: ['none', 'read'],
14
+ packages: ['none', 'read', 'write'],
15
+ pages: ['none', 'read', 'write'],
16
+ 'pull-requests': ['none', 'read', 'write'],
17
+ 'repository-projects': ['none', 'read', 'write'],
18
+ 'security-events': ['none', 'read', 'write'],
19
+ statuses: ['none', 'read', 'write'],
20
+ 'vulnerability-alerts': ['none', 'read'],
21
+ };
22
+ export function isPlainRecord(value) {
23
+ if (value == null || typeof value !== 'object' || Array.isArray(value))
24
+ return false;
25
+ const prototype = Object.getPrototypeOf(value);
26
+ return prototype === Object.prototype || prototype === null;
27
+ }
28
+ export function isValidPermissionMap(value) {
29
+ if (!isPlainRecord(value))
30
+ return false;
31
+ return Object.entries(value).every(([scope, level]) => {
32
+ const allowed = Object.hasOwn(LEVELS_BY_SCOPE, scope)
33
+ ? LEVELS_BY_SCOPE[scope]
34
+ : undefined;
35
+ return typeof level === 'string' && allowed?.includes(level) === true;
36
+ });
37
+ }
38
+ export function isValidDeclaration(value) {
39
+ return value === 'read-all' || isValidPermissionMap(value);
40
+ }
41
+ export function permissionMap(value) {
42
+ if (value === 'read-all') {
43
+ return new Map(Object.entries(LEVELS_BY_SCOPE)
44
+ .filter(([, levels]) => levels.includes('read'))
45
+ .map(([scope]) => [scope, 'read']));
46
+ }
47
+ return new Map(Object.entries(value).filter(([, level]) => level !== 'none'));
48
+ }
49
+ export function mergePermissionMaps(target, source) {
50
+ for (const [scope, level] of source) {
51
+ const current = target.get(scope) ?? 'none';
52
+ if (PERMISSION_LEVEL_RANK[level] > PERMISSION_LEVEL_RANK[current])
53
+ target.set(scope, level);
54
+ }
55
+ }
@@ -0,0 +1,8 @@
1
+ import type { Workflow } from './permissions.mts';
2
+ export declare function inheritanceAwarePermissionMismatches(args: {
3
+ callerPath: string;
4
+ callerJobKey: string;
5
+ callerWorkflow: Workflow;
6
+ calleePath: string;
7
+ calleeWorkflow: Workflow;
8
+ }): string[];
@@ -0,0 +1,88 @@
1
+ import { isPlainRecord, isValidDeclaration, isValidPermissionMap, mergePermissionMaps, permissionMap, PERMISSION_LEVEL_RANK, } from './permission-declarations.mjs';
2
+ function sortedEntries(value) {
3
+ return [...value].toSorted(([left], [right]) => left.localeCompare(right));
4
+ }
5
+ function formatMap(value) {
6
+ return JSON.stringify(Object.fromEntries(sortedEntries(value)));
7
+ }
8
+ function diagnostic(callerPath, callerJobKey, calleePath, detail) {
9
+ return ` ${callerPath} job "${callerJobKey}" → ${calleePath}: ${detail}`;
10
+ }
11
+ export function inheritanceAwarePermissionMismatches(args) {
12
+ const prefix = (detail) => diagnostic(args.callerPath, args.callerJobKey, args.calleePath, detail);
13
+ const callerJob = args.callerWorkflow.jobs?.[args.callerJobKey];
14
+ const callerPermissions = callerJob?.permissions;
15
+ if (callerPermissions === 'write-all')
16
+ return [prefix('caller grants write-all')];
17
+ if (callerJob == null ||
18
+ !Object.hasOwn(callerJob, 'permissions') ||
19
+ !isValidPermissionMap(callerPermissions)) {
20
+ return [prefix('caller permissions must be an explicit map')];
21
+ }
22
+ const jobsPresent = Object.hasOwn(args.calleeWorkflow, 'jobs');
23
+ const jobsValue = args.calleeWorkflow.jobs;
24
+ if (jobsPresent && !isPlainRecord(jobsValue))
25
+ return [prefix('callee jobs are invalid')];
26
+ const calleeJobEntries = Object.entries(isPlainRecord(jobsValue) ? jobsValue : {});
27
+ const invalidJobKeys = [];
28
+ const calleeJobs = [];
29
+ for (const [key, job] of calleeJobEntries) {
30
+ if (isPlainRecord(job))
31
+ calleeJobs.push([key, job]);
32
+ else
33
+ invalidJobKeys.push(key);
34
+ }
35
+ if (invalidJobKeys.length > 0) {
36
+ return invalidJobKeys.map((key) => prefix(`callee job "${key}" is invalid`));
37
+ }
38
+ const topLevelPresent = Object.hasOwn(args.calleeWorkflow, 'permissions');
39
+ const topLevelPermissions = args.calleeWorkflow.permissions;
40
+ let validatedTopLevelPermissions;
41
+ if (topLevelPresent) {
42
+ if (topLevelPermissions === 'write-all')
43
+ return [prefix('callee requires write-all')];
44
+ if (!isValidDeclaration(topLevelPermissions)) {
45
+ return [prefix('callee top-level permissions are invalid')];
46
+ }
47
+ validatedTopLevelPermissions = topLevelPermissions;
48
+ }
49
+ if (calleeJobs.length === 0)
50
+ return [prefix('callee must declare at least one job')];
51
+ const invalidJobs = [];
52
+ const validatedJobPermissions = [];
53
+ let requiresWriteAll = false;
54
+ for (const [key, job] of calleeJobs) {
55
+ if (!Object.hasOwn(job, 'permissions'))
56
+ continue;
57
+ if (job.permissions === 'write-all') {
58
+ requiresWriteAll = true;
59
+ }
60
+ else if (isValidDeclaration(job.permissions)) {
61
+ validatedJobPermissions.push(job.permissions);
62
+ }
63
+ else {
64
+ invalidJobs.push(prefix(`callee job "${key}" permissions are invalid`));
65
+ }
66
+ }
67
+ if (invalidJobs.length > 0)
68
+ return invalidJobs;
69
+ if (requiresWriteAll)
70
+ return [prefix('callee requires write-all')];
71
+ const callerMap = permissionMap(callerPermissions);
72
+ const calleeMap = new Map();
73
+ if (validatedTopLevelPermissions !== undefined) {
74
+ mergePermissionMaps(calleeMap, permissionMap(validatedTopLevelPermissions));
75
+ }
76
+ for (const permissions of validatedJobPermissions) {
77
+ mergePermissionMaps(calleeMap, permissionMap(permissions));
78
+ }
79
+ const calleeFitsCaller = [...calleeMap].every(([scope, level]) => {
80
+ const callerLevel = callerMap.get(scope) ?? 'none';
81
+ return PERMISSION_LEVEL_RANK[callerLevel] >= PERMISSION_LEVEL_RANK[level];
82
+ });
83
+ const hasCallerInheritance = !topLevelPresent && calleeJobs.some(([, job]) => !Object.hasOwn(job, 'permissions'));
84
+ const permissionsMatch = JSON.stringify(sortedEntries(callerMap)) === JSON.stringify(sortedEntries(calleeMap));
85
+ if (calleeFitsCaller && (hasCallerInheritance || permissionsMatch))
86
+ return [];
87
+ return [prefix(`caller grants ${formatMap(callerMap)}, callee requires ${formatMap(calleeMap)}`)];
88
+ }
@@ -1,3 +1,6 @@
1
1
  import type { WorkflowTopology } from './types.mts';
2
2
  import { type Workflow } from './permissions.mts';
3
- export declare function callerCalleePermissionMismatches(topology: WorkflowTopology, documents: Readonly<Record<string, Workflow>>): string[];
3
+ export type CallerCalleePermissionPolicy = {
4
+ comparison: 'exact' | 'inheritance-aware';
5
+ };
6
+ export declare function callerCalleePermissionMismatches(topology: WorkflowTopology, documents: Readonly<Record<string, Workflow>>, policy?: CallerCalleePermissionPolicy): string[];
@@ -1,4 +1,5 @@
1
1
  import { parsePermissions, permissionsToMap, requiredWorkflowPermissions, } from './permissions.mjs';
2
+ import { inheritanceAwarePermissionMismatches } from './permission-inheritance.mjs';
2
3
  function formatPermissions(value) {
3
4
  if (value === null)
4
5
  return 'none';
@@ -6,7 +7,7 @@ function formatPermissions(value) {
6
7
  return value;
7
8
  return JSON.stringify(Object.fromEntries([...value].toSorted(([a], [b]) => a.localeCompare(b))));
8
9
  }
9
- export function callerCalleePermissionMismatches(topology, documents) {
10
+ export function callerCalleePermissionMismatches(topology, documents, policy = { comparison: 'exact' }) {
10
11
  const mismatches = [];
11
12
  const jobsById = new Map(topology.jobs.map((job) => [job.id, job]));
12
13
  const workflowsById = new Map(topology.workflows.map((workflow) => [workflow.id, workflow]));
@@ -22,14 +23,24 @@ export function callerCalleePermissionMismatches(topology, documents) {
22
23
  if (!caller)
23
24
  throw new Error(`missing workflow document: ${callerPath}`);
24
25
  const job = caller.jobs?.[callerJob.key];
25
- if (!job)
26
+ if (policy.comparison === 'exact' && !job)
26
27
  continue;
27
28
  const calleePath = callee.path;
28
29
  const calleeWorkflow = documents[calleePath];
29
30
  if (!calleeWorkflow)
30
31
  throw new Error(`missing workflow document: ${calleePath}`);
32
+ if (policy.comparison === 'inheritance-aware') {
33
+ mismatches.push(...inheritanceAwarePermissionMismatches({
34
+ callerPath,
35
+ callerJobKey: callerJob.key,
36
+ callerWorkflow: caller,
37
+ calleePath,
38
+ calleeWorkflow,
39
+ }));
40
+ continue;
41
+ }
31
42
  const calleePerms = requiredWorkflowPermissions(calleeWorkflow);
32
- const jobPerms = parsePermissions(job.permissions);
43
+ const jobPerms = parsePermissions(job?.permissions);
33
44
  if (jobPerms == null) {
34
45
  mismatches.push(` ${callerPath} job "${callerJob.key}" → ${calleePath}: missing explicit job-level permissions`);
35
46
  continue;
@@ -37,7 +37,24 @@ const guardCoversConsumer = conditionEntails('always()', 'failure()')
37
37
 
38
38
  The permission comparison expects documents for every local caller and callable callee in the
39
39
  topology. The consumer reads workflow files and decides which inventory entries are provisioned;
40
- these functions never fetch secret values. Readiness checks rely on the parser's
40
+ these functions never fetch secret values. The two-argument permission comparison requires exact
41
+ caller/callee grants for compatibility. Consumers that intentionally let a reusable workflow job
42
+ inherit the caller's token can opt into the fail-closed inheritance policy:
43
+
44
+ ```ts
45
+ callerCalleePermissionMismatches(topology, documents, {
46
+ comparison: 'inheritance-aware',
47
+ })
48
+ ```
49
+
50
+ This mode requires an explicit caller permission map, rejects malformed declarations and
51
+ `write-all`, and permits extra caller grants only when the callee omits top-level permissions and
52
+ at least one callee job omits its own permissions. Explicit grants from every callee job still form
53
+ required minima that must fit within the caller grants, including jobs guarded by `if`. The strict
54
+ scope model follows GitHub's
55
+ [workflow permission syntax](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#permissions).
56
+
57
+ Readiness checks rely on the parser's
41
58
  `secretReferences` at workflow, job, and step scope. A missing required secret is considered ready
42
59
  only when a preceding guarded `run` step binds it to an env var, checks that var for emptiness,
43
60
  and exits with status 1. Optional `workflow_call` secrets are exempt.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vouchington-tooling",
3
- "version": "0.22.1",
3
+ "version": "0.24.0",
4
4
  "description": "Vouchington CLI and extractable tooling libraries.",
5
5
  "homepage": "https://github.com/vouchington/vouchington-tooling/tree/main/packages/vouchington-tooling#readme",
6
6
  "bugs": {
@@ -13,6 +13,11 @@ Use before implementation. Inspect checkout status without discarding work; foll
13
13
  worktree, contribution, and CI policy. Read every applicable `AGENTS.md` from the repository root
14
14
  through changed files, plus relevant documentation and tests. Local instructions govern this skill.
15
15
 
16
+ Use [PR descriptions](../pr-description/SKILL.md) before creating or updating a pull request.
17
+ Diagnose failed CI with [CI-log review](../review-ci-logs/SKILL.md), then update confirmed harness
18
+ gaps before handoff. Keep those records after checks pass; routine local successes stay in the
19
+ evidence record.
20
+
16
21
  - During implementation, use [implementation](references/implementation.md).
17
22
  - Before handoff, use [evidence sweep](references/evidence-sweep.md).
18
23
  - For review, use [review](references/review.md).
@@ -5,3 +5,6 @@ contract compatibility, failure paths, authorization, untrusted input, secrets,
5
5
  boundaries. Remove dead paths and stale documentation rather than labeling them as legacy.
6
6
 
7
7
  Record unresolved risk as an explicit accepted decision or follow-up, never as an unnoticed gap.
8
+ Check the pull-request description against the final behavior and audience impact. After CI
9
+ diagnosis, ensure confirmed local-verification gaps or local/CI mismatches and their correction
10
+ remain disclosed; passing checks do not erase the gap discovered earlier.
@@ -13,18 +13,38 @@ Use when the current repository provides a journal, blackboard, or equivalent du
13
13
  record. Read local `AGENTS.md` for the provider, credential, retention, and
14
14
  subagent-identity rules.
15
15
 
16
- 1. Append a concise note when a check fails, permission is denied, scope changes, a repeated fix is
17
- needed, or a tool result reveals a reusable gap. Include the finding, affected paths, concrete
18
- evidence, and any tracking reference.
19
- 2. Preserve the provider's required session and parent-session identity.
20
- - Do not invent, guess, print, search for, or persist a credential outside its documented
21
- mechanism.
22
- - When the provider supports repository metadata, keep the cumulative canonical repository list
23
- on that agent's own session. Tag each entry with only the repositories relevant to it.
24
- - Update session metadata before appending. Stop if that update fails.
25
- 3. If the journal service cannot authenticate or persist a mandatory entry, stop and report the
26
- blocker rather than silently substituting a local file or memory.
27
- 4. Read journal entries oldest-first when preparing a retrospective or clustering follow-ups; use
28
- direct evidence rather than reconstructing events from memory.
16
+ 1. Capture consequential observations before filing an issue: failed or recovered checks, denied or
17
+ approved permissions, repeated fixes, scope changes, first-party tool behavior, and architectural
18
+ findings. Record useful resolved outcomes as well as unresolved gaps. Include bounded evidence,
19
+ affected areas, an explicit disposition, and an existing tracking reference when present.
20
+ Journal meaningful skips or bypasses of applicable configured workflows before completion, with
21
+ the owning workflow or command-catalog entrypoint, reason, and observed result/action.
22
+ 2. Use the shared validated envelope with storage `type: journal` or `retrospective`, canonical exact
23
+ entry repositories, stable `sourceEventId`, work outcome, and explicit feedback coverage. Category
24
+ is optional context; it never changes storage type or distillation eligibility. Generate routine
25
+ facts and metadata through the approved composer instead of hand-authoring factual markers.
26
+ 3. Preserve exact provider session and parent identities. Each agent writes only its own session.
27
+ Update that session's cumulative repository union before appending; never infer another repository
28
+ from prose or create a child identity from a model guess.
29
+ 4. Select the repository's trusted mode explicitly. Interactive outages may retain validated,
30
+ sanitized feedback in the bounded durable outbox. Report pending count and delivery state, replay
31
+ with the same source identity, and continue primary work only after persistence succeeds. A full,
32
+ unsafe, or unwritable outbox blocks capture; never evict or silently discard an unsent record.
33
+ 5. Autonomous runners require online session ensure, a fresh admission write, and readback before
34
+ launching an attempt. Terminal reporting preserves work outcome separately from feedback
35
+ coverage and delivery. A filesystem outbox never grants admission or acknowledged completion.
36
+ 6. Use at-least-once delivery with consumer deduplication by exact session/source identity. A
37
+ transport timeout can leave a late durable write; pending or blocked is never an acknowledged
38
+ receipt. Replay verifies matching content before retrying and rejects conflicting source reuse.
39
+ 7. Read journal entries oldest-first for retrospectives. Record explicit none-observed with inspected
40
+ scope, or not-assessed/unavailable with reason, when evidence does not establish a finding. A
41
+ permission request is not proof of approval or denial; localhost refusal is not proof of sandbox
42
+ enforcement. Mark partial capture and dropped counts instead of reporting clean evidence.
29
43
 
30
- Consumer wrapper owns: service, command, note grammar, archival policy, and issue destination.
44
+ Never search for, print, invent, or mint credentials. Durable entries and outbox records contain only
45
+ bounded structured facts or sanitized summaries, never raw command output, transcript content,
46
+ environment dumps, provider payloads, or secrets. Known-secret redaction supplements the author's
47
+ minimization responsibility; it cannot prove arbitrary prose contains no undisclosed secret.
48
+
49
+ Consumer wrappers own service configuration, trusted mode selection, commands, outbox location,
50
+ issue routing, and archival authorization.
@@ -4,9 +4,9 @@
4
4
  {
5
5
  "name": "agent-workflow",
6
6
  "plugin": "vouchington-workflow",
7
- "pluginVersion": "0.8.0",
7
+ "pluginVersion": "0.9.0",
8
8
  "path": "agent-workflow/SKILL.md",
9
- "prerequisites": ["github-issue"]
9
+ "prerequisites": ["github-issue", "pr-description", "review-ci-logs"]
10
10
  },
11
11
  {
12
12
  "name": "backend-vitest-test-authoring",
@@ -18,13 +18,13 @@
18
18
  {
19
19
  "name": "blackboard",
20
20
  "plugin": "vouchington-workflow",
21
- "pluginVersion": "0.8.0",
21
+ "pluginVersion": "0.9.0",
22
22
  "path": "blackboard/SKILL.md"
23
23
  },
24
24
  {
25
25
  "name": "dependabot",
26
26
  "plugin": "vouchington-workflow",
27
- "pluginVersion": "0.8.0",
27
+ "pluginVersion": "0.9.0",
28
28
  "path": "dependabot/SKILL.md",
29
29
  "prerequisites": ["github-actions-checklist"]
30
30
  },
@@ -38,26 +38,26 @@
38
38
  {
39
39
  "name": "git-commit-checklist",
40
40
  "plugin": "vouchington-workflow",
41
- "pluginVersion": "0.8.0",
41
+ "pluginVersion": "0.9.0",
42
42
  "path": "git-commit-checklist/SKILL.md"
43
43
  },
44
44
  {
45
45
  "name": "github-actions-authoring",
46
46
  "plugin": "vouchington-workflow",
47
- "pluginVersion": "0.8.0",
47
+ "pluginVersion": "0.9.0",
48
48
  "path": "github-actions-authoring/SKILL.md",
49
49
  "prerequisites": ["github-actions-checklist"]
50
50
  },
51
51
  {
52
52
  "name": "github-actions-checklist",
53
53
  "plugin": "vouchington-workflow",
54
- "pluginVersion": "0.8.0",
54
+ "pluginVersion": "0.9.0",
55
55
  "path": "github-actions-checklist/SKILL.md"
56
56
  },
57
57
  {
58
58
  "name": "github-issue",
59
59
  "plugin": "vouchington-workflow",
60
- "pluginVersion": "0.8.0",
60
+ "pluginVersion": "0.9.0",
61
61
  "path": "github-issue/SKILL.md"
62
62
  },
63
63
  {
@@ -70,26 +70,26 @@
70
70
  {
71
71
  "name": "npm-publishing",
72
72
  "plugin": "vouchington-workflow",
73
- "pluginVersion": "0.8.0",
73
+ "pluginVersion": "0.9.0",
74
74
  "path": "npm-publishing/SKILL.md"
75
75
  },
76
76
  {
77
77
  "name": "organize-github-issues",
78
78
  "plugin": "vouchington-workflow",
79
- "pluginVersion": "0.8.0",
79
+ "pluginVersion": "0.9.0",
80
80
  "path": "organize-github-issues/SKILL.md",
81
81
  "prerequisites": ["github-issue"]
82
82
  },
83
83
  {
84
84
  "name": "package-json-checklist",
85
85
  "plugin": "vouchington-workflow",
86
- "pluginVersion": "0.8.0",
86
+ "pluginVersion": "0.9.0",
87
87
  "path": "package-json-checklist/SKILL.md"
88
88
  },
89
89
  {
90
90
  "name": "planning",
91
91
  "plugin": "vouchington-workflow",
92
- "pluginVersion": "0.8.0",
92
+ "pluginVersion": "0.9.0",
93
93
  "path": "planning/SKILL.md",
94
94
  "prerequisites": ["github-issue"]
95
95
  },
@@ -115,53 +115,53 @@
115
115
  {
116
116
  "name": "pr-description",
117
117
  "plugin": "vouchington-workflow",
118
- "pluginVersion": "0.8.0",
118
+ "pluginVersion": "0.9.0",
119
119
  "path": "pr-description/SKILL.md"
120
120
  },
121
121
  {
122
122
  "name": "retrospective",
123
123
  "plugin": "vouchington-workflow",
124
- "pluginVersion": "0.8.0",
124
+ "pluginVersion": "0.9.0",
125
125
  "path": "retrospective/SKILL.md"
126
126
  },
127
127
  {
128
128
  "name": "retrospective-distill",
129
129
  "plugin": "vouchington-workflow",
130
- "pluginVersion": "0.8.0",
130
+ "pluginVersion": "0.9.0",
131
131
  "path": "retrospective-distill/SKILL.md",
132
132
  "prerequisites": ["github-issue"]
133
133
  },
134
134
  {
135
135
  "name": "review-ci-logs",
136
136
  "plugin": "vouchington-workflow",
137
- "pluginVersion": "0.8.0",
137
+ "pluginVersion": "0.9.0",
138
138
  "path": "review-ci-logs/SKILL.md",
139
- "prerequisites": ["github-actions-checklist"]
139
+ "prerequisites": ["github-actions-checklist", "pr-description"]
140
140
  },
141
141
  {
142
142
  "name": "review-github-issue-taxonomy",
143
143
  "plugin": "vouchington-workflow",
144
- "pluginVersion": "0.8.0",
144
+ "pluginVersion": "0.9.0",
145
145
  "path": "review-github-issue-taxonomy/SKILL.md",
146
146
  "prerequisites": ["github-issue"]
147
147
  },
148
148
  {
149
149
  "name": "revisit-followups",
150
150
  "plugin": "vouchington-workflow",
151
- "pluginVersion": "0.8.0",
151
+ "pluginVersion": "0.9.0",
152
152
  "path": "revisit-followups/SKILL.md",
153
153
  "prerequisites": ["github-issue"]
154
154
  },
155
155
  {
156
156
  "name": "stacked-prs",
157
157
  "plugin": "vouchington-workflow",
158
- "pluginVersion": "0.8.0",
158
+ "pluginVersion": "0.9.0",
159
159
  "path": "stacked-prs/SKILL.md"
160
160
  },
161
161
  {
162
162
  "name": "static-analysis-checklist",
163
163
  "plugin": "vouchington-workflow",
164
- "pluginVersion": "0.8.0",
164
+ "pluginVersion": "0.9.0",
165
165
  "path": "static-analysis-checklist/SKILL.md",
166
166
  "prerequisites": ["github-actions-checklist"]
167
167
  },
@@ -9,20 +9,54 @@ Read applicable `AGENTS.md` and their declared adapter alias, otherwise
9
9
  `.agents/skills/pr-description/SKILL.md` from the repository root if present.
10
10
  Local policy overrides these defaults; do not reload an already-read adapter or canonical skill.
11
11
 
12
- Use before opening or updating a pull request, or when reviewing PR hand-off quality. Read local
12
+ Use before opening or updating a pull request, after diagnosing a CI failure, or at handoff. Read local
13
13
  `AGENTS.md`, pull-request template, and issue-linking policy first.
14
14
 
15
- Include enough context for a reviewer with no prior conversation:
15
+ Keep the description understandable without the conversation. Its short visible core explains:
16
16
 
17
- - A concise summary of what changed and why.
18
- - The underlying root cause for a fix, not only its visible symptom.
19
- - Validation performed and any intentionally skipped checks with reasons.
20
- - Rollout, compatibility, operational safety, and follow-up context when the change affects a live
21
- or independently deployed surface.
22
- - Correct issue relationships: close only issues fully resolved and explain any non-closing links.
23
- - A compact diagram only when it materially clarifies a multi-component flow or lifecycle.
17
+ - **Summary:** what changed, why, and the concrete before/after behavior. For a fix, explain its
18
+ root cause as well as the symptom. A reader should understand the outcome before implementation
19
+ details.
20
+ - **Impact:** who or what is affected and how their behavior changes. Name the actual audience,
21
+ such as end users, staff, API clients, operators, or contributors. Keep material risks and
22
+ limitations visible. For internal work, describe the affected development or operational flow.
24
23
 
25
- Use the repository's approved PR tooling and preserve sections managed by its review automation.
24
+ Add detail only where the change warrants it:
25
+
26
+ - For cost changes, state the direction and scope. Label figures as measured or estimated, name the
27
+ workload and assumptions, and link evidence. Say unmeasured when no defensible figure exists;
28
+ do not invent savings or claim a neutral cost without evidence. Follow the consumer's privacy
29
+ policy before reporting actual spending, and use approved aggregated or redacted evidence.
30
+ - For database changes, inventory added, removed, and changed tables, columns, constraints, and
31
+ indexes. Explain the relationships and conformance to the consumer's schema rules, including
32
+ producer/consumer changes and any justified exceptions. Link the policy and concrete evidence.
33
+ - For API, workflow, or independently deployed changes, explain the affected contract, lifecycle,
34
+ or operational safety. Follow the consumer's compatibility and deployment policy.
35
+ - Use a before/after table or meaningful Mermaid diagram when it makes behavior, relationships,
36
+ workflow topology, or lifecycle easier to understand. Prose is sufficient for a simple change.
37
+
38
+ Put long comparisons, inventories, diagrams, calculations, and failure evidence in collapsed
39
+ `<details>` sections. Keep the short conclusions and material risks outside them. Keep the
40
+ consumer's required visible core headings outside disclosure containers. Put opening/closing tags
41
+ on separate lines, with a blank line after `</summary>` and before `</details>` so Markdown renders.
42
+ Read [description examples](references/examples.md) when choosing a comparison, diagram, or failure
43
+ record.
44
+
45
+ Do not fill the description with routine local successful-test lists. This is a reporting rule,
46
+ not permission to skip checks: execute required validation and retain its revision, exact scope,
47
+ result, and any omission reason in the work's evidence record.
48
+
49
+ Include **Harness gaps** only after CI diagnosis establishes an omitted local verification or a
50
+ proven local/CI mismatch. Link the first failing run/job and its exact head revision, compare the actual local and
51
+ CI scope, explain the omission or difference, and record the durable correction or authorized
52
+ linked follow-up. Distinguish an omitted check from one that passed locally. Unknown coverage is
53
+ not evidence of a miss; classify genuine CI-only or external infrastructure failures separately.
54
+ Retain confirmed gap records after CI turns green. Diagnose the failure through the repository's
55
+ CI investigation workflow; a failed status alone does not establish a gap.
56
+
57
+ Use the repository's approved PR tooling and preserve sections managed by its review automation
58
+ verbatim. Close only issues fully resolved and explain non-closing issue links. Apply this guidance
59
+ to descriptions being created or updated, not a bulk rewrite of historical pull requests.
26
60
 
27
61
  Consumer wrapper owns: required headings, source-issue rule, merge policy, repository command, and
28
62
  hosted review system.