quantum-reasoning-skill 1.0.0 → 1.1.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/LICENSE +21 -21
- package/README.md +86 -133
- package/SKILL.md +146 -146
- package/VERSION +1 -1
- package/index.js +207 -1
- package/package.json +41 -1
- package/.github/ISSUE_TEMPLATE/benchmark-result.yml +0 -81
- package/.github/ISSUE_TEMPLATE/bug-report.yml +0 -38
- package/.github/ISSUE_TEMPLATE/feature-request.yml +0 -31
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -15
- package/.github/workflows/npm-publish.yml +0 -32
- package/.github/workflows/publish-release.yml +0 -79
- package/.github/workflows/validate-skill.yml +0 -154
- package/CHANGELOG.md +0 -51
- package/CITATION.cff +0 -17
- package/CONTRIBUTING.md +0 -88
- package/SECURITY.md +0 -17
- package/benchmark/README.md +0 -134
- package/benchmark/cases.jsonl +0 -6
- package/benchmark/evaluate.py +0 -257
- package/benchmark/schemas/case.schema.json +0 -20
- package/benchmark/schemas/comparison.schema.json +0 -64
- package/benchmark/schemas/metadata.schema.json +0 -53
- package/benchmark/schemas/result.schema.json +0 -25
- package/benchmark/validate_submission.py +0 -114
- package/docs/COMPATIBILITY.md +0 -44
- package/docs/MEASUREMENT.md +0 -131
- package/examples/host-integration.md +0 -57
- package/examples/usage.md +0 -31
- package/reference/branch_controller.py +0 -256
- package/tests/test_benchmark.py +0 -120
- package/tests/test_reference.py +0 -128
- package/tests/test_submission_validation.py +0 -78
package/index.js
CHANGED
|
@@ -1 +1,207 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* quantum-reasoning-skill
|
|
6
|
+
*
|
|
7
|
+
* A real, executable entry point for the Node/MCP host ecosystem. It reads the
|
|
8
|
+
* skill contract that ships with this package and exposes it programmatically
|
|
9
|
+
* and from the command line.
|
|
10
|
+
*
|
|
11
|
+
* The previous implementation did `require('./SKILL.md')`, which made Node
|
|
12
|
+
* parse Markdown as JavaScript and throw a SyntaxError on every import.
|
|
13
|
+
* SKILL.md is now read as text via fs.readFileSync.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const REQUIRED_FIELDS = ['name', 'description'];
|
|
20
|
+
|
|
21
|
+
const SKILL_FILE = path.join(__dirname, 'SKILL.md');
|
|
22
|
+
const VERSION_FILE = path.join(__dirname, 'VERSION');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parse leading `---` delimited front matter from the skill document.
|
|
26
|
+
* Deliberately dependency-free: the contract only uses `key: value` pairs.
|
|
27
|
+
*
|
|
28
|
+
* @param {string} text
|
|
29
|
+
* @returns {{fields: Record<string,string>, fenceEnd: number}}
|
|
30
|
+
*/
|
|
31
|
+
function parseFrontMatter(text) {
|
|
32
|
+
const lines = text.split(/\r?\n/);
|
|
33
|
+
if (lines.length === 0 || lines[0].trim() !== '---') {
|
|
34
|
+
throw new Error('SKILL.md must start with a `---` front matter fence');
|
|
35
|
+
}
|
|
36
|
+
let fenceEnd = -1;
|
|
37
|
+
for (let i = 1; i < lines.length; i += 1) {
|
|
38
|
+
if (lines[i].trim() === '---') {
|
|
39
|
+
fenceEnd = i;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (fenceEnd === -1) {
|
|
44
|
+
throw new Error('SKILL.md front matter is not closed');
|
|
45
|
+
}
|
|
46
|
+
const fields = Object.create(null);
|
|
47
|
+
for (const line of lines.slice(1, fenceEnd)) {
|
|
48
|
+
const trimmed = line.trim();
|
|
49
|
+
if (trimmed === '' || trimmed.startsWith('#')) continue;
|
|
50
|
+
const idx = trimmed.indexOf(':');
|
|
51
|
+
if (idx === -1) continue;
|
|
52
|
+
const key = trimmed.slice(0, idx).trim();
|
|
53
|
+
let value = trimmed.slice(idx + 1).trim();
|
|
54
|
+
if (
|
|
55
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
56
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
57
|
+
) {
|
|
58
|
+
value = value.slice(1, -1);
|
|
59
|
+
}
|
|
60
|
+
fields[key] = value;
|
|
61
|
+
}
|
|
62
|
+
return { fields, fenceEnd };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Read the packaged skill contract from disk.
|
|
67
|
+
*
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
function readSkillDocument() {
|
|
71
|
+
return fs.readFileSync(SKILL_FILE, 'utf8');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Read the packaged VERSION file.
|
|
76
|
+
*
|
|
77
|
+
* @returns {string}
|
|
78
|
+
*/
|
|
79
|
+
function readVersion() {
|
|
80
|
+
const raw = fs.readFileSync(VERSION_FILE, 'utf8').trim();
|
|
81
|
+
return raw.startsWith('v') ? raw.slice(1) : raw;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Validate the skill contract.
|
|
86
|
+
*
|
|
87
|
+
* @param {string} text
|
|
88
|
+
* @returns {{name: string, description: string, descriptionLength: number,
|
|
89
|
+
* bodyLines: number, valid: boolean, problems: string[]}}
|
|
90
|
+
*/
|
|
91
|
+
function validateSkill(text) {
|
|
92
|
+
const { fields, fenceEnd } = parseFrontMatter(text);
|
|
93
|
+
const problems = [];
|
|
94
|
+
for (const field of REQUIRED_FIELDS) {
|
|
95
|
+
if (!fields[field]) {
|
|
96
|
+
problems.push(`front matter must define a non-empty \`${field}\``);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (fields.name && fields.name !== 'quantum-reasoning') {
|
|
100
|
+
problems.push('front matter `name` must be `quantum-reasoning`');
|
|
101
|
+
}
|
|
102
|
+
const bodyLines = text.split(/\r?\n/).slice(fenceEnd + 1).length;
|
|
103
|
+
if (bodyLines < 20) {
|
|
104
|
+
problems.push(`SKILL.md body is too short (${bodyLines} lines, expected >= 20)`);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
name: fields.name || '',
|
|
108
|
+
description: fields.description || '',
|
|
109
|
+
descriptionLength: (fields.description || '').length,
|
|
110
|
+
bodyLines,
|
|
111
|
+
valid: problems.length === 0,
|
|
112
|
+
problems,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Load and validate the packaged skill in one call.
|
|
118
|
+
*
|
|
119
|
+
* @returns {object} the parsed skill definition
|
|
120
|
+
*/
|
|
121
|
+
function loadSkill() {
|
|
122
|
+
const document = readSkillDocument();
|
|
123
|
+
const { fields } = parseFrontMatter(document);
|
|
124
|
+
const report = validateSkill(document);
|
|
125
|
+
return {
|
|
126
|
+
name: report.name,
|
|
127
|
+
description: report.description,
|
|
128
|
+
version: readVersion(),
|
|
129
|
+
document,
|
|
130
|
+
valid: report.valid,
|
|
131
|
+
problems: report.problems,
|
|
132
|
+
metadata: fields,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const USAGE = `quantum-reasoning — inspect the packaged skill contract
|
|
137
|
+
|
|
138
|
+
Usage:
|
|
139
|
+
quantum-reasoning Print the skill summary
|
|
140
|
+
quantum-reasoning --json Print the full report as JSON
|
|
141
|
+
quantum-reasoning --validate Exit non-zero if the contract is invalid
|
|
142
|
+
quantum-reasoning --path Print the absolute SKILL.md path
|
|
143
|
+
quantum-reasoning --help Show this message
|
|
144
|
+
|
|
145
|
+
Exit codes:
|
|
146
|
+
0 success
|
|
147
|
+
1 invalid skill contract (--validate)
|
|
148
|
+
2 SKILL.md could not be read
|
|
149
|
+
`;
|
|
150
|
+
|
|
151
|
+
function main(argv) {
|
|
152
|
+
const args = argv.slice(2);
|
|
153
|
+
const wantsJson = args.includes('--json');
|
|
154
|
+
const wantsValidate = args.includes('--validate');
|
|
155
|
+
const wantsPath = args.includes('--path');
|
|
156
|
+
|
|
157
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
158
|
+
process.stdout.write(USAGE);
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let report;
|
|
163
|
+
try {
|
|
164
|
+
report = validateSkill(readSkillDocument());
|
|
165
|
+
} catch (error) {
|
|
166
|
+
process.stderr.write(`error: ${error.message}\n`);
|
|
167
|
+
return 2;
|
|
168
|
+
}
|
|
169
|
+
report.version = readVersion();
|
|
170
|
+
report.path = SKILL_FILE;
|
|
171
|
+
|
|
172
|
+
if (wantsPath) {
|
|
173
|
+
process.stdout.write(`${SKILL_FILE}\n`);
|
|
174
|
+
return 0;
|
|
175
|
+
}
|
|
176
|
+
if (wantsJson) {
|
|
177
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
178
|
+
} else {
|
|
179
|
+
process.stdout.write(`skill: ${report.name || '<missing name>'}\n`);
|
|
180
|
+
process.stdout.write(`status: ${report.valid ? 'valid' : 'INVALID'}\n`);
|
|
181
|
+
process.stdout.write(`file: ${SKILL_FILE}\n`);
|
|
182
|
+
process.stdout.write(`version: ${report.version}\n`);
|
|
183
|
+
process.stdout.write(`body: ${report.bodyLines} lines\n`);
|
|
184
|
+
for (const problem of report.problems) {
|
|
185
|
+
process.stdout.write(` - ${problem}\n`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (wantsValidate && !report.valid) {
|
|
189
|
+
return 1;
|
|
190
|
+
}
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = {
|
|
195
|
+
name: 'quantum-reasoning-skill',
|
|
196
|
+
version: readVersion(),
|
|
197
|
+
skillFile: SKILL_FILE,
|
|
198
|
+
parseFrontMatter,
|
|
199
|
+
readSkillDocument,
|
|
200
|
+
readVersion,
|
|
201
|
+
validateSkill,
|
|
202
|
+
loadSkill,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
if (require.main === module) {
|
|
206
|
+
process.exitCode = main(process.argv);
|
|
207
|
+
}
|
package/package.json
CHANGED
|
@@ -1 +1,41 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "quantum-reasoning-skill",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Quantum-inspired reasoning skill for exploring multiple solution paths",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"quantum-reasoning": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"SKILL.md",
|
|
12
|
+
"VERSION",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "node index.js --validate && node -e \"const s=require('./index.js'); if(!s.loadSkill().valid){console.error('skill contract invalid');process.exit(1)}\""
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"ai-agents",
|
|
24
|
+
"reasoning",
|
|
25
|
+
"quantum-inspired",
|
|
26
|
+
"multi-branch",
|
|
27
|
+
"agent-skills",
|
|
28
|
+
"mcp",
|
|
29
|
+
"claude-skill"
|
|
30
|
+
],
|
|
31
|
+
"author": "Furox-Art",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/Furox-Art/quantum-reasoning-skill.git"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/Furox-Art/quantum-reasoning-skill/issues"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/Furox-Art/quantum-reasoning-skill#readme"
|
|
41
|
+
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
name: Benchmark result
|
|
2
|
-
description: Submit an independently run baseline-vs-skill model evaluation
|
|
3
|
-
title: "[Benchmark] "
|
|
4
|
-
labels: []
|
|
5
|
-
body:
|
|
6
|
-
- type: markdown
|
|
7
|
-
attributes:
|
|
8
|
-
value: |
|
|
9
|
-
Submit reproducible measurements only. Do not include private chain-of-thought. For PR submissions, validate the full bundle with `python benchmark/validate_submission.py --root benchmark/results/community`.
|
|
10
|
-
|
|
11
|
-
- type: input
|
|
12
|
-
id: provider
|
|
13
|
-
attributes:
|
|
14
|
-
label: Provider
|
|
15
|
-
placeholder: Provider or local runtime
|
|
16
|
-
validations:
|
|
17
|
-
required: true
|
|
18
|
-
|
|
19
|
-
- type: input
|
|
20
|
-
id: model
|
|
21
|
-
attributes:
|
|
22
|
-
label: Exact model / version
|
|
23
|
-
placeholder: Exact model identifier and version if available
|
|
24
|
-
validations:
|
|
25
|
-
required: true
|
|
26
|
-
|
|
27
|
-
- type: input
|
|
28
|
-
id: skill_version
|
|
29
|
-
attributes:
|
|
30
|
-
label: Skill version / commit
|
|
31
|
-
placeholder: v0.3.1 or commit SHA
|
|
32
|
-
validations:
|
|
33
|
-
required: true
|
|
34
|
-
|
|
35
|
-
- type: input
|
|
36
|
-
id: run_date
|
|
37
|
-
attributes:
|
|
38
|
-
label: Run date
|
|
39
|
-
placeholder: YYYY-MM-DD
|
|
40
|
-
validations:
|
|
41
|
-
required: true
|
|
42
|
-
|
|
43
|
-
- type: textarea
|
|
44
|
-
id: controls
|
|
45
|
-
attributes:
|
|
46
|
-
label: Experimental controls
|
|
47
|
-
description: Describe sampling settings, context/output limits, tools, repetitions, seeds, prompt wrapper and hardware/runtime when relevant.
|
|
48
|
-
validations:
|
|
49
|
-
required: true
|
|
50
|
-
|
|
51
|
-
- type: textarea
|
|
52
|
-
id: artifacts
|
|
53
|
-
attributes:
|
|
54
|
-
label: Result artifacts
|
|
55
|
-
description: Link or attach metadata.json, cases.jsonl, baseline.jsonl, skill.jsonl, comparison.json and README.md. State whether the bundle passed validate_submission.py.
|
|
56
|
-
validations:
|
|
57
|
-
required: true
|
|
58
|
-
|
|
59
|
-
- type: textarea
|
|
60
|
-
id: summary
|
|
61
|
-
attributes:
|
|
62
|
-
label: Result summary
|
|
63
|
-
description: Report accuracy and compute/cost trade-offs. Include failures, refusals and timeouts.
|
|
64
|
-
validations:
|
|
65
|
-
required: true
|
|
66
|
-
|
|
67
|
-
- type: checkboxes
|
|
68
|
-
id: integrity
|
|
69
|
-
attributes:
|
|
70
|
-
label: Integrity checks
|
|
71
|
-
options:
|
|
72
|
-
- label: Baseline and skill used the same model/version, task set, tools, sampling settings and budget policy.
|
|
73
|
-
required: true
|
|
74
|
-
- label: I included the exact evaluated cases and did not remove failed runs, refusals or timeouts.
|
|
75
|
-
required: true
|
|
76
|
-
- label: comparison.json was generated from the submitted raw files and was not edited to improve the result.
|
|
77
|
-
required: true
|
|
78
|
-
- label: I did not include private chain-of-thought or fabricate unavailable telemetry.
|
|
79
|
-
required: true
|
|
80
|
-
- label: I disclosed modifications to SKILL.md, benchmark cases, wrappers or provider adapters.
|
|
81
|
-
required: true
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
name: Bug report
|
|
2
|
-
description: Report a reproducible defect in the skill, reference controller, benchmark tooling, or CI.
|
|
3
|
-
title: "[Bug]: "
|
|
4
|
-
labels: ["bug"]
|
|
5
|
-
body:
|
|
6
|
-
- type: textarea
|
|
7
|
-
id: summary
|
|
8
|
-
attributes:
|
|
9
|
-
label: What happened?
|
|
10
|
-
description: Describe the observed behavior and what you expected instead.
|
|
11
|
-
validations:
|
|
12
|
-
required: true
|
|
13
|
-
- type: textarea
|
|
14
|
-
id: reproduce
|
|
15
|
-
attributes:
|
|
16
|
-
label: Minimal reproduction
|
|
17
|
-
description: Include commands, inputs, or a small example that reproduces the problem.
|
|
18
|
-
validations:
|
|
19
|
-
required: true
|
|
20
|
-
- type: input
|
|
21
|
-
id: version
|
|
22
|
-
attributes:
|
|
23
|
-
label: Repository version or commit
|
|
24
|
-
placeholder: v0.3.0 or commit SHA
|
|
25
|
-
validations:
|
|
26
|
-
required: true
|
|
27
|
-
- type: textarea
|
|
28
|
-
id: environment
|
|
29
|
-
attributes:
|
|
30
|
-
label: Environment
|
|
31
|
-
description: Python version, host/agent integration, OS, and relevant tool versions.
|
|
32
|
-
- type: checkboxes
|
|
33
|
-
id: sensitive
|
|
34
|
-
attributes:
|
|
35
|
-
label: Safety check
|
|
36
|
-
options:
|
|
37
|
-
- label: I have not included secrets, credentials, private chain-of-thought, or sensitive benchmark data.
|
|
38
|
-
required: true
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
name: Feature request
|
|
2
|
-
description: Propose a change to the reasoning protocol, tooling, benchmarks, or integration contract.
|
|
3
|
-
title: "[Feature]: "
|
|
4
|
-
labels: ["enhancement"]
|
|
5
|
-
body:
|
|
6
|
-
- type: textarea
|
|
7
|
-
id: problem
|
|
8
|
-
attributes:
|
|
9
|
-
label: Problem or limitation
|
|
10
|
-
description: What concrete limitation does this proposal address?
|
|
11
|
-
validations:
|
|
12
|
-
required: true
|
|
13
|
-
- type: textarea
|
|
14
|
-
id: proposal
|
|
15
|
-
attributes:
|
|
16
|
-
label: Proposed change
|
|
17
|
-
description: Describe the behavior or interface you want to add or change.
|
|
18
|
-
validations:
|
|
19
|
-
required: true
|
|
20
|
-
- type: textarea
|
|
21
|
-
id: evidence
|
|
22
|
-
attributes:
|
|
23
|
-
label: Evidence or evaluation plan
|
|
24
|
-
description: If this affects reasoning quality, explain how it could be tested without relying on anecdotal examples alone.
|
|
25
|
-
- type: checkboxes
|
|
26
|
-
id: scope
|
|
27
|
-
attributes:
|
|
28
|
-
label: Scope check
|
|
29
|
-
options:
|
|
30
|
-
- label: This proposal does not present unverified benchmark claims as established results.
|
|
31
|
-
required: true
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
## Summary
|
|
2
|
-
|
|
3
|
-
Describe the change and the behavior it affects.
|
|
4
|
-
|
|
5
|
-
## Validation
|
|
6
|
-
|
|
7
|
-
- [ ] I ran `python -m unittest discover -s tests -v`.
|
|
8
|
-
- [ ] I ran `python benchmark/evaluate.py --help`.
|
|
9
|
-
- [ ] I added or updated tests when executable behavior changed.
|
|
10
|
-
- [ ] I updated documentation when the public contract changed.
|
|
11
|
-
- [ ] I did not include private chain-of-thought, secrets, credentials, or fabricated benchmark telemetry.
|
|
12
|
-
|
|
13
|
-
## Benchmark-impacting changes
|
|
14
|
-
|
|
15
|
-
If this changes `SKILL.md`, scoring, collapse/revival behavior, benchmark schemas, or evaluation logic, explain how existing results should be interpreted and whether new community runs are needed.
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: npm Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_dispatch:
|
|
5
|
-
push:
|
|
6
|
-
branches: [main]
|
|
7
|
-
paths:
|
|
8
|
-
- "package.json"
|
|
9
|
-
- "index.js"
|
|
10
|
-
|
|
11
|
-
concurrency:
|
|
12
|
-
group: npm-publish
|
|
13
|
-
cancel-in-progress: false
|
|
14
|
-
|
|
15
|
-
permissions:
|
|
16
|
-
contents: read
|
|
17
|
-
|
|
18
|
-
jobs:
|
|
19
|
-
publish:
|
|
20
|
-
runs-on: ubuntu-latest
|
|
21
|
-
steps:
|
|
22
|
-
- uses: actions/checkout@v4
|
|
23
|
-
|
|
24
|
-
- uses: actions/setup-node@v4
|
|
25
|
-
with:
|
|
26
|
-
node-version: "20"
|
|
27
|
-
registry-url: "https://registry.npmjs.org"
|
|
28
|
-
|
|
29
|
-
- name: Publish to npm
|
|
30
|
-
run: npm publish --access public
|
|
31
|
-
env:
|
|
32
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
name: publish-release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_run:
|
|
5
|
-
workflows: ["validate-skill"]
|
|
6
|
-
types: [completed]
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
permissions:
|
|
10
|
-
contents: write
|
|
11
|
-
|
|
12
|
-
concurrency:
|
|
13
|
-
group: publish-release
|
|
14
|
-
cancel-in-progress: false
|
|
15
|
-
|
|
16
|
-
jobs:
|
|
17
|
-
publish:
|
|
18
|
-
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
19
|
-
runs-on: ubuntu-latest
|
|
20
|
-
steps:
|
|
21
|
-
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
22
|
-
with:
|
|
23
|
-
ref: ${{ github.event.workflow_run.head_sha }}
|
|
24
|
-
fetch-depth: 0
|
|
25
|
-
|
|
26
|
-
- name: Resolve and validate version
|
|
27
|
-
id: version
|
|
28
|
-
shell: bash
|
|
29
|
-
run: |
|
|
30
|
-
set -euo pipefail
|
|
31
|
-
test -s VERSION
|
|
32
|
-
version="$(tr -d '[:space:]' < VERSION)"
|
|
33
|
-
version="${version#v}"
|
|
34
|
-
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then
|
|
35
|
-
echo "Invalid release version: $version" >&2
|
|
36
|
-
exit 1
|
|
37
|
-
fi
|
|
38
|
-
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
39
|
-
echo "tag=v${version}" >> "$GITHUB_OUTPUT"
|
|
40
|
-
|
|
41
|
-
- name: Require matching changelog entry
|
|
42
|
-
shell: bash
|
|
43
|
-
env:
|
|
44
|
-
VERSION: ${{ steps.version.outputs.version }}
|
|
45
|
-
run: |
|
|
46
|
-
set -euo pipefail
|
|
47
|
-
grep -Fq "## [$VERSION]" CHANGELOG.md || {
|
|
48
|
-
echo "CHANGELOG.md must contain a ## [$VERSION] section before release." >&2
|
|
49
|
-
exit 1
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
- name: Check existing release
|
|
53
|
-
id: existing
|
|
54
|
-
shell: bash
|
|
55
|
-
env:
|
|
56
|
-
GH_TOKEN: ${{ github.token }}
|
|
57
|
-
TAG: ${{ steps.version.outputs.tag }}
|
|
58
|
-
run: |
|
|
59
|
-
set -euo pipefail
|
|
60
|
-
if gh release view "$TAG" >/dev/null 2>&1; then
|
|
61
|
-
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
62
|
-
echo "$TAG already exists; nothing to publish."
|
|
63
|
-
else
|
|
64
|
-
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
65
|
-
fi
|
|
66
|
-
|
|
67
|
-
- name: Create tag and GitHub Release
|
|
68
|
-
if: steps.existing.outputs.exists != 'true'
|
|
69
|
-
shell: bash
|
|
70
|
-
env:
|
|
71
|
-
GH_TOKEN: ${{ github.token }}
|
|
72
|
-
TAG: ${{ steps.version.outputs.tag }}
|
|
73
|
-
TARGET_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
74
|
-
run: |
|
|
75
|
-
set -euo pipefail
|
|
76
|
-
gh release create "$TAG" \
|
|
77
|
-
--target "$TARGET_SHA" \
|
|
78
|
-
--title "$TAG" \
|
|
79
|
-
--generate-notes
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
name: validate-skill
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
pull_request:
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: read
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
validate:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
|
|
15
|
-
|
|
16
|
-
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
17
|
-
with:
|
|
18
|
-
python-version: "3.12"
|
|
19
|
-
|
|
20
|
-
- name: Validate skill repository contract
|
|
21
|
-
shell: bash
|
|
22
|
-
run: |
|
|
23
|
-
set -euo pipefail
|
|
24
|
-
for required in \
|
|
25
|
-
SKILL.md README.md LICENSE CHANGELOG.md VERSION CONTRIBUTING.md SECURITY.md CITATION.cff \
|
|
26
|
-
examples/usage.md examples/host-integration.md \
|
|
27
|
-
reference/branch_controller.py \
|
|
28
|
-
docs/MEASUREMENT.md docs/COMPATIBILITY.md \
|
|
29
|
-
benchmark/README.md benchmark/cases.jsonl benchmark/evaluate.py benchmark/validate_submission.py \
|
|
30
|
-
benchmark/schemas/case.schema.json benchmark/schemas/result.schema.json \
|
|
31
|
-
benchmark/schemas/metadata.schema.json benchmark/schemas/comparison.schema.json \
|
|
32
|
-
tests/test_reference.py tests/test_benchmark.py tests/test_submission_validation.py \
|
|
33
|
-
.github/ISSUE_TEMPLATE/benchmark-result.yml .github/ISSUE_TEMPLATE/bug-report.yml \
|
|
34
|
-
.github/ISSUE_TEMPLATE/feature-request.yml .github/PULL_REQUEST_TEMPLATE.md; do
|
|
35
|
-
test -s "$required"
|
|
36
|
-
done
|
|
37
|
-
|
|
38
|
-
python - <<'PY'
|
|
39
|
-
from pathlib import Path
|
|
40
|
-
import json
|
|
41
|
-
import re
|
|
42
|
-
|
|
43
|
-
root = Path.cwd().resolve()
|
|
44
|
-
skill = (root / "SKILL.md").read_text(encoding="utf-8")
|
|
45
|
-
lines = skill.splitlines()
|
|
46
|
-
if not lines or lines[0].strip() != "---":
|
|
47
|
-
raise SystemExit("SKILL.md must start with YAML front matter")
|
|
48
|
-
try:
|
|
49
|
-
end = next(i for i, line in enumerate(lines[1:], start=1) if line.strip() == "---")
|
|
50
|
-
except StopIteration as exc:
|
|
51
|
-
raise SystemExit("SKILL.md front matter is not closed") from exc
|
|
52
|
-
fields = {}
|
|
53
|
-
for line in lines[1:end]:
|
|
54
|
-
if ":" in line:
|
|
55
|
-
key, value = line.split(":", 1)
|
|
56
|
-
fields[key.strip()] = value.strip()
|
|
57
|
-
if fields.get("name") != "quantum-reasoning":
|
|
58
|
-
raise SystemExit("SKILL.md front matter must declare name: quantum-reasoning")
|
|
59
|
-
if not fields.get("description"):
|
|
60
|
-
raise SystemExit("SKILL.md front matter must contain a non-empty description")
|
|
61
|
-
if len(lines[end + 1:]) < 20:
|
|
62
|
-
raise SystemExit("SKILL.md body is unexpectedly short")
|
|
63
|
-
|
|
64
|
-
readme = (root / "README.md").read_text(encoding="utf-8")
|
|
65
|
-
for required in (
|
|
66
|
-
"SKILL.md", "examples/usage.md", "examples/host-integration.md",
|
|
67
|
-
"reference/branch_controller.py", "docs/MEASUREMENT.md", "docs/COMPATIBILITY.md",
|
|
68
|
-
"benchmark/README.md", "CONTRIBUTING.md", "SECURITY.md", "CITATION.cff",
|
|
69
|
-
):
|
|
70
|
-
if required not in readme:
|
|
71
|
-
raise SystemExit(f"README.md must reference {required}")
|
|
72
|
-
|
|
73
|
-
markdown_files = [
|
|
74
|
-
root / "README.md", root / "SKILL.md", root / "CONTRIBUTING.md", root / "SECURITY.md",
|
|
75
|
-
root / "examples/usage.md", root / "examples/host-integration.md",
|
|
76
|
-
root / "benchmark/README.md", root / "docs/MEASUREMENT.md", root / "docs/COMPATIBILITY.md",
|
|
77
|
-
]
|
|
78
|
-
link_pattern = re.compile(r"\[[^\]]*\]\(([^)]+)\)")
|
|
79
|
-
for document in markdown_files:
|
|
80
|
-
text = document.read_text(encoding="utf-8")
|
|
81
|
-
for raw_target in link_pattern.findall(text):
|
|
82
|
-
target = raw_target.strip().split("#", 1)[0].split("?", 1)[0]
|
|
83
|
-
if not target or "://" in target or target.startswith(("mailto:", "#")):
|
|
84
|
-
continue
|
|
85
|
-
resolved = (document.parent / target).resolve()
|
|
86
|
-
try:
|
|
87
|
-
resolved.relative_to(root)
|
|
88
|
-
except ValueError as exc:
|
|
89
|
-
raise SystemExit(f"{document.relative_to(root)} links outside repository: {raw_target}") from exc
|
|
90
|
-
if not resolved.exists():
|
|
91
|
-
raise SystemExit(f"Broken relative link in {document.relative_to(root)}: {raw_target}")
|
|
92
|
-
|
|
93
|
-
case_path = root / "benchmark" / "cases.jsonl"
|
|
94
|
-
seen_ids = set()
|
|
95
|
-
for line_number, raw in enumerate(case_path.read_text(encoding="utf-8").splitlines(), start=1):
|
|
96
|
-
if not raw.strip():
|
|
97
|
-
continue
|
|
98
|
-
try:
|
|
99
|
-
case = json.loads(raw)
|
|
100
|
-
except json.JSONDecodeError as exc:
|
|
101
|
-
raise SystemExit(f"benchmark/cases.jsonl:{line_number}: invalid JSON: {exc}") from exc
|
|
102
|
-
required = {"id", "domain", "prompt", "accepted_answers"}
|
|
103
|
-
missing = required - set(case)
|
|
104
|
-
if missing:
|
|
105
|
-
raise SystemExit(f"benchmark/cases.jsonl:{line_number}: missing {sorted(missing)}")
|
|
106
|
-
case_id = str(case["id"])
|
|
107
|
-
if case_id in seen_ids:
|
|
108
|
-
raise SystemExit(f"duplicate benchmark case id: {case_id}")
|
|
109
|
-
seen_ids.add(case_id)
|
|
110
|
-
if not isinstance(case["accepted_answers"], list) or not case["accepted_answers"]:
|
|
111
|
-
raise SystemExit(f"benchmark/cases.jsonl:{line_number}: accepted_answers must be non-empty")
|
|
112
|
-
|
|
113
|
-
schemas = sorted((root / "benchmark" / "schemas").glob("*.schema.json"))
|
|
114
|
-
if len(schemas) < 4:
|
|
115
|
-
raise SystemExit("expected case, result, metadata and comparison JSON Schemas")
|
|
116
|
-
for schema_path in schemas:
|
|
117
|
-
schema = json.loads(schema_path.read_text(encoding="utf-8"))
|
|
118
|
-
if schema.get("$schema") != "https://json-schema.org/draft/2020-12/schema":
|
|
119
|
-
raise SystemExit(f"{schema_path}: expected JSON Schema draft 2020-12")
|
|
120
|
-
if schema.get("type") != "object" or not schema.get("required"):
|
|
121
|
-
raise SystemExit(f"{schema_path}: must define an object with required fields")
|
|
122
|
-
|
|
123
|
-
version = (root / "VERSION").read_text(encoding="utf-8").strip().lstrip("v")
|
|
124
|
-
if not re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+(?:[.-][0-9A-Za-z.-]+)?", version):
|
|
125
|
-
raise SystemExit("VERSION is not a valid semantic version")
|
|
126
|
-
cff = (root / "CITATION.cff").read_text(encoding="utf-8")
|
|
127
|
-
for marker in ("cff-version: 1.2.0", "title:", "authors:", "repository-code:", "license: MIT"):
|
|
128
|
-
if marker not in cff:
|
|
129
|
-
raise SystemExit(f"CITATION.cff missing {marker!r}")
|
|
130
|
-
if f"version: {version}" not in cff:
|
|
131
|
-
raise SystemExit("CITATION.cff version must match VERSION")
|
|
132
|
-
|
|
133
|
-
action_use = re.compile(r"uses:\s+(actions/[A-Za-z0-9_.-]+)@([^\s#]+)")
|
|
134
|
-
for workflow in (root / ".github" / "workflows").glob("*.yml"):
|
|
135
|
-
for action, ref in action_use.findall(workflow.read_text(encoding="utf-8")):
|
|
136
|
-
if not re.fullmatch(r"[0-9a-f]{40}", ref):
|
|
137
|
-
raise SystemExit(f"{workflow}: {action} must be pinned to an exact commit SHA")
|
|
138
|
-
|
|
139
|
-
print("Skill repository contract validated successfully.")
|
|
140
|
-
PY
|
|
141
|
-
|
|
142
|
-
- name: Compile Python sources
|
|
143
|
-
run: python -m compileall -q reference benchmark tests
|
|
144
|
-
|
|
145
|
-
- name: Run behavioral tests
|
|
146
|
-
run: python -m unittest discover -s tests -v
|
|
147
|
-
|
|
148
|
-
- name: Validate community benchmark bundles
|
|
149
|
-
run: python benchmark/validate_submission.py --root benchmark/results/community --allow-empty
|
|
150
|
-
|
|
151
|
-
- name: Check benchmark CLIs
|
|
152
|
-
run: |
|
|
153
|
-
python benchmark/evaluate.py --help > /dev/null
|
|
154
|
-
python benchmark/validate_submission.py --help > /dev/null
|