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.
- package/README.md +102 -4
- package/dist/agent-blackboard/client.d.mts +34 -0
- package/dist/agent-blackboard/client.mjs +41 -0
- package/dist/agent-blackboard/feedback-canonical.d.mts +1 -0
- package/dist/agent-blackboard/feedback-canonical.mjs +13 -0
- package/dist/agent-blackboard/feedback-codec.d.mts +7 -0
- package/dist/agent-blackboard/feedback-codec.mjs +121 -0
- package/dist/agent-blackboard/feedback-compose.d.mts +37 -0
- package/dist/agent-blackboard/feedback-compose.mjs +109 -0
- package/dist/agent-blackboard/feedback-deadline.d.mts +1 -0
- package/dist/agent-blackboard/feedback-deadline.mjs +18 -0
- package/dist/agent-blackboard/feedback-delivery.d.mts +18 -0
- package/dist/agent-blackboard/feedback-delivery.mjs +88 -0
- package/dist/agent-blackboard/feedback-fields.d.mts +4 -0
- package/dist/agent-blackboard/feedback-fields.mjs +38 -0
- package/dist/agent-blackboard/feedback-identity.d.mts +2 -0
- package/dist/agent-blackboard/feedback-identity.mjs +29 -0
- package/dist/agent-blackboard/feedback-online-error.d.mts +7 -0
- package/dist/agent-blackboard/feedback-online-error.mjs +23 -0
- package/dist/agent-blackboard/feedback-online.d.mts +2 -0
- package/dist/agent-blackboard/feedback-online.mjs +137 -0
- package/dist/agent-blackboard/feedback-outbox.d.mts +8 -0
- package/dist/agent-blackboard/feedback-outbox.mjs +157 -0
- package/dist/agent-blackboard/feedback-types.d.mts +66 -0
- package/dist/agent-blackboard/feedback-types.mjs +1 -0
- package/dist/agent-blackboard/index.d.mts +16 -39
- package/dist/agent-blackboard/index.mjs +35 -81
- package/dist/cli/commands/agent-blackboard.mjs +35 -4
- package/dist/cli/usage.d.mts +1 -1
- package/dist/cli/usage.mjs +3 -1
- package/dist/markdown/details-scope.d.mts +13 -0
- package/dist/markdown/details-scope.mjs +73 -0
- package/dist/markdown/document-sections.d.mts +3 -0
- package/dist/markdown/document-sections.mjs +64 -0
- package/dist/markdown/document-types.d.mts +21 -0
- package/dist/markdown/document-types.mjs +1 -0
- package/dist/markdown/index.d.mts +3 -0
- package/dist/markdown/index.mjs +2 -0
- package/dist/markdown/validate-sections.d.mts +3 -0
- package/dist/markdown/validate-sections.mjs +34 -0
- package/dist/retrospective-facts/coverage.d.mts +6 -0
- package/dist/retrospective-facts/coverage.mjs +42 -0
- package/dist/retrospective-facts/index.d.mts +3 -0
- package/dist/retrospective-facts/index.mjs +18 -1
- package/dist/retrospective-transcript/codex.mjs +8 -3
- package/dist/retrospective-transcript/index.d.mts +5 -0
- package/dist/retrospective-transcript/index.mjs +29 -9
- package/dist/session-friction/classify.mjs +25 -14
- package/dist/session-friction/coverage-ledger.d.mts +10 -0
- package/dist/session-friction/coverage-ledger.mjs +75 -0
- package/dist/session-friction/index.d.mts +1 -1
- package/dist/session-friction/log-file.d.mts +2 -2
- package/dist/session-friction/log-file.mjs +22 -10
- package/dist/session-friction/log.mjs +57 -10
- package/dist/session-friction/report.mjs +36 -7
- package/dist/session-friction/sandbox.mjs +11 -4
- package/dist/session-friction/types.d.mts +25 -4
- package/dist/workflow-policy/index.d.mts +1 -1
- package/dist/workflow-policy/index.mjs +1 -1
- package/dist/workflow-policy/permission-declarations.d.mts +14 -0
- package/dist/workflow-policy/permission-declarations.mjs +55 -0
- package/dist/workflow-policy/permission-inheritance.d.mts +8 -0
- package/dist/workflow-policy/permission-inheritance.mjs +88 -0
- package/dist/workflow-policy/permission-mismatches.d.mts +4 -1
- package/dist/workflow-policy/permission-mismatches.mjs +14 -3
- package/docs/workflow-and-compiler.md +18 -1
- package/package.json +1 -1
- package/skills/agent-workflow/SKILL.md +5 -0
- package/skills/agent-workflow/references/review.md +3 -0
- package/skills/blackboard/SKILL.md +34 -14
- package/skills/manifest.json +21 -21
- package/skills/pr-description/SKILL.md +44 -10
- package/skills/pr-description/references/examples.md +136 -0
- package/skills/retrospective/SKILL.md +27 -16
- package/skills/retrospective-distill/SKILL.md +15 -6
- 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,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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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.
|
package/skills/manifest.json
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
{
|
|
5
5
|
"name": "agent-workflow",
|
|
6
6
|
"plugin": "vouchington-workflow",
|
|
7
|
-
"pluginVersion": "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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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
|
-
|
|
15
|
+
Keep the description understandable without the conversation. Its short visible core explains:
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
or
|
|
22
|
-
|
|
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
|
-
|
|
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.
|