audrey 0.23.1 → 1.0.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/CHANGELOG.md +81 -19
- package/LICENSE +21 -21
- package/README.md +209 -5
- package/SECURITY.md +2 -1
- package/benchmarks/adapter-kit.mjs +20 -0
- package/benchmarks/adapter-self-test.mjs +166 -0
- package/benchmarks/adapters/example-allow.mjs +28 -0
- package/benchmarks/adapters/mem0-platform.mjs +267 -0
- package/benchmarks/adapters/registry.json +51 -0
- package/benchmarks/adapters/zep-cloud.mjs +280 -0
- package/benchmarks/baselines.js +169 -0
- package/benchmarks/build-leaderboard.mjs +170 -0
- package/benchmarks/cases.js +537 -0
- package/benchmarks/create-conformance-card.mjs +139 -0
- package/benchmarks/create-submission-bundle.mjs +176 -0
- package/benchmarks/dry-run-external-adapters.mjs +165 -0
- package/benchmarks/guardbench.js +1035 -0
- package/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +50 -0
- package/benchmarks/output/external/guardbench-external-dry-run.json +69 -0
- package/benchmarks/output/external/guardbench-external-evidence.json +56 -0
- package/benchmarks/output/guardbench-conformance-card.json +63 -0
- package/benchmarks/output/guardbench-manifest.json +414 -0
- package/benchmarks/output/guardbench-raw.json +1171 -0
- package/benchmarks/output/guardbench-summary.json +1981 -0
- package/benchmarks/output/leaderboard/guardbench-leaderboard.json +93 -0
- package/benchmarks/output/leaderboard/guardbench-leaderboard.md +7 -0
- package/benchmarks/output/submission-bundle/guardbench-conformance-card.json +63 -0
- package/benchmarks/output/submission-bundle/guardbench-manifest.json +414 -0
- package/benchmarks/output/submission-bundle/guardbench-raw.json +1171 -0
- package/benchmarks/output/submission-bundle/guardbench-summary.json +1981 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-conformance-card.schema.json +184 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-evidence.schema.json +108 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-external-run.schema.json +160 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-leaderboard.schema.json +179 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-manifest.schema.json +213 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-publication-verification.schema.json +47 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-raw.schema.json +164 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/benchmarks/output/submission-bundle/schemas/guardbench-summary.schema.json +228 -0
- package/benchmarks/output/submission-bundle/submission-manifest.json +131 -0
- package/benchmarks/output/submission-bundle/validation-report.json +31 -0
- package/benchmarks/output/summary.json +2354 -0
- package/benchmarks/perf-snapshot.js +304 -0
- package/benchmarks/perf.bench.js +161 -0
- package/benchmarks/public-paths.mjs +78 -0
- package/benchmarks/reference-results.js +70 -0
- package/benchmarks/report.js +259 -0
- package/benchmarks/run-external-guardbench.mjs +281 -0
- package/benchmarks/run.js +682 -0
- package/benchmarks/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/benchmarks/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/benchmarks/schemas/guardbench-conformance-card.schema.json +184 -0
- package/benchmarks/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/benchmarks/schemas/guardbench-external-evidence.schema.json +108 -0
- package/benchmarks/schemas/guardbench-external-run.schema.json +160 -0
- package/benchmarks/schemas/guardbench-leaderboard.schema.json +179 -0
- package/benchmarks/schemas/guardbench-manifest.schema.json +213 -0
- package/benchmarks/schemas/guardbench-publication-verification.schema.json +47 -0
- package/benchmarks/schemas/guardbench-raw.schema.json +164 -0
- package/benchmarks/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/benchmarks/schemas/guardbench-summary.schema.json +228 -0
- package/benchmarks/snapshots/perf-0.22.2.json +123 -0
- package/benchmarks/snapshots/perf-0.23.0.json +123 -0
- package/benchmarks/validate-adapter-module.mjs +104 -0
- package/benchmarks/validate-adapter-registry.mjs +134 -0
- package/benchmarks/validate-adapter-self-test.mjs +96 -0
- package/benchmarks/validate-guardbench-artifacts.mjs +343 -0
- package/benchmarks/verify-external-evidence.mjs +296 -0
- package/benchmarks/verify-publication-artifacts.mjs +286 -0
- package/benchmarks/verify-submission-bundle.mjs +167 -0
- package/dist/mcp-server/config.d.ts +1 -1
- package/dist/mcp-server/config.d.ts.map +1 -1
- package/dist/mcp-server/config.js +1 -1
- package/dist/mcp-server/config.js.map +1 -1
- package/dist/mcp-server/index.d.ts +65 -3
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/index.js +675 -157
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/src/action-key.d.ts +9 -0
- package/dist/src/action-key.d.ts.map +1 -0
- package/dist/src/action-key.js +49 -0
- package/dist/src/action-key.js.map +1 -0
- package/dist/src/adaptive.js +5 -5
- package/dist/src/affect.js +8 -8
- package/dist/src/audrey.d.ts +3 -0
- package/dist/src/audrey.d.ts.map +1 -1
- package/dist/src/audrey.js +55 -3
- package/dist/src/audrey.js.map +1 -1
- package/dist/src/capsule.js +4 -4
- package/dist/src/causal.js +3 -3
- package/dist/src/consolidate.js +48 -48
- package/dist/src/controller.d.ts +61 -5
- package/dist/src/controller.d.ts.map +1 -1
- package/dist/src/controller.js +230 -49
- package/dist/src/controller.js.map +1 -1
- package/dist/src/db.js +172 -172
- package/dist/src/decay.js +8 -8
- package/dist/src/embedding.d.ts +2 -1
- package/dist/src/embedding.d.ts.map +1 -1
- package/dist/src/embedding.js +39 -29
- package/dist/src/embedding.js.map +1 -1
- package/dist/src/encode.js +6 -6
- package/dist/src/feedback.d.ts +6 -0
- package/dist/src/feedback.d.ts.map +1 -1
- package/dist/src/feedback.js +6 -0
- package/dist/src/feedback.js.map +1 -1
- package/dist/src/forget.js +12 -12
- package/dist/src/hybrid-recall.js +9 -9
- package/dist/src/impact.js +6 -6
- package/dist/src/import.d.ts +3 -3
- package/dist/src/import.js +41 -41
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/interference.js +14 -14
- package/dist/src/introspect.js +18 -18
- package/dist/src/preflight.d.ts.map +1 -1
- package/dist/src/preflight.js +41 -0
- package/dist/src/preflight.js.map +1 -1
- package/dist/src/promote.js +7 -7
- package/dist/src/prompts.js +118 -118
- package/dist/src/recall.js +30 -30
- package/dist/src/reflexes.d.ts +1 -0
- package/dist/src/reflexes.d.ts.map +1 -1
- package/dist/src/reflexes.js +3 -0
- package/dist/src/reflexes.js.map +1 -1
- package/dist/src/rollback.js +4 -4
- package/dist/src/routes.d.ts.map +1 -1
- package/dist/src/routes.js +67 -1
- package/dist/src/routes.js.map +1 -1
- package/dist/src/validate.js +25 -25
- package/docs/AUDREY_PAPER_OUTLINE.md +175 -0
- package/docs/MEMORY_BENCHMARKING.md +59 -0
- package/docs/PRODUCTION_BACKLOG.md +304 -0
- package/docs/paper/00-master.md +48 -0
- package/docs/paper/01-introduction.md +27 -0
- package/docs/paper/02-related-work.md +47 -0
- package/docs/paper/03-problem-definition.md +108 -0
- package/docs/paper/04-design.md +164 -0
- package/docs/paper/05-guardbench-spec.md +412 -0
- package/docs/paper/06-implementation.md +113 -0
- package/docs/paper/07-evaluation.md +168 -0
- package/docs/paper/08-discussion-limitations.md +61 -0
- package/docs/paper/09-conclusion.md +11 -0
- package/docs/paper/SUBMISSION_README.md +162 -0
- package/docs/paper/appendix-a-demo-transcript.md +114 -0
- package/docs/paper/arxiv-compile-report.schema.json +116 -0
- package/docs/paper/arxiv-source.schema.json +61 -0
- package/docs/paper/audrey-paper-v1.md +1106 -0
- package/docs/paper/browser-launch-plan.json +209 -0
- package/docs/paper/browser-launch-plan.schema.json +100 -0
- package/docs/paper/browser-launch-results.json +86 -0
- package/docs/paper/browser-launch-results.schema.json +66 -0
- package/docs/paper/claim-register.json +138 -0
- package/docs/paper/claim-register.schema.json +81 -0
- package/docs/paper/evidence-ledger.md +103 -0
- package/docs/paper/output/arxiv/README-arxiv.txt +8 -0
- package/docs/paper/output/arxiv/arxiv-manifest.json +41 -0
- package/docs/paper/output/arxiv/main.tex +949 -0
- package/docs/paper/output/arxiv/references.bib +222 -0
- package/docs/paper/output/arxiv-compile-report.json +24 -0
- package/docs/paper/output/submission-bundle/LICENSE +21 -0
- package/docs/paper/output/submission-bundle/README.md +533 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +50 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-dry-run.json +69 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-evidence.json +56 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-conformance-card.json +63 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-manifest.json +414 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-raw.json +1171 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-summary.json +1981 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.json +93 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.md +7 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/submission-manifest.json +131 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/validation-report.json +31 -0
- package/docs/paper/output/submission-bundle/benchmarks/output/summary.json +2354 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-adapter-registry.schema.json +69 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-adapter-self-test.schema.json +156 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-conformance-card.schema.json +184 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-dry-run.schema.json +74 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-evidence.schema.json +108 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-external-run.schema.json +160 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-leaderboard.schema.json +179 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-manifest.schema.json +213 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-publication-verification.schema.json +47 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-raw.schema.json +164 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-submission-manifest.schema.json +151 -0
- package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-summary.schema.json +228 -0
- package/docs/paper/output/submission-bundle/docs/AUDREY_PAPER_OUTLINE.md +175 -0
- package/docs/paper/output/submission-bundle/docs/paper/00-master.md +48 -0
- package/docs/paper/output/submission-bundle/docs/paper/01-introduction.md +27 -0
- package/docs/paper/output/submission-bundle/docs/paper/02-related-work.md +47 -0
- package/docs/paper/output/submission-bundle/docs/paper/03-problem-definition.md +108 -0
- package/docs/paper/output/submission-bundle/docs/paper/04-design.md +164 -0
- package/docs/paper/output/submission-bundle/docs/paper/05-guardbench-spec.md +412 -0
- package/docs/paper/output/submission-bundle/docs/paper/06-implementation.md +113 -0
- package/docs/paper/output/submission-bundle/docs/paper/07-evaluation.md +168 -0
- package/docs/paper/output/submission-bundle/docs/paper/08-discussion-limitations.md +61 -0
- package/docs/paper/output/submission-bundle/docs/paper/09-conclusion.md +11 -0
- package/docs/paper/output/submission-bundle/docs/paper/SUBMISSION_README.md +162 -0
- package/docs/paper/output/submission-bundle/docs/paper/appendix-a-demo-transcript.md +114 -0
- package/docs/paper/output/submission-bundle/docs/paper/arxiv-compile-report.schema.json +116 -0
- package/docs/paper/output/submission-bundle/docs/paper/arxiv-source.schema.json +61 -0
- package/docs/paper/output/submission-bundle/docs/paper/audrey-paper-v1.md +1106 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-plan.json +209 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-plan.schema.json +100 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-results.json +86 -0
- package/docs/paper/output/submission-bundle/docs/paper/browser-launch-results.schema.json +66 -0
- package/docs/paper/output/submission-bundle/docs/paper/claim-register.json +138 -0
- package/docs/paper/output/submission-bundle/docs/paper/claim-register.schema.json +81 -0
- package/docs/paper/output/submission-bundle/docs/paper/evidence-ledger.md +103 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/README-arxiv.txt +8 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/arxiv-manifest.json +41 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/main.tex +949 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/references.bib +222 -0
- package/docs/paper/output/submission-bundle/docs/paper/output/arxiv-compile-report.json +24 -0
- package/docs/paper/output/submission-bundle/docs/paper/paper-submission-bundle.schema.json +70 -0
- package/docs/paper/output/submission-bundle/docs/paper/publication-pack.json +81 -0
- package/docs/paper/output/submission-bundle/docs/paper/publication-pack.schema.json +60 -0
- package/docs/paper/output/submission-bundle/docs/paper/references.bib +222 -0
- package/docs/paper/output/submission-bundle/package.json +212 -0
- package/docs/paper/output/submission-bundle/paper-submission-manifest.json +379 -0
- package/docs/paper/paper-submission-bundle.schema.json +70 -0
- package/docs/paper/publication-pack.json +81 -0
- package/docs/paper/publication-pack.schema.json +60 -0
- package/docs/paper/references.bib +222 -0
- package/package.json +87 -4
- package/scripts/audit-release-completion.mjs +362 -0
- package/scripts/create-arxiv-source.mjs +362 -0
- package/scripts/create-paper-submission-bundle.mjs +210 -0
- package/scripts/finalize-release.mjs +526 -0
- package/scripts/prepare-release-cut.mjs +269 -0
- package/scripts/publish-release-bundle.mjs +209 -0
- package/scripts/publish-release-github-api.mjs +429 -0
- package/scripts/run-vitest.mjs +34 -0
- package/scripts/smoke-cli.js +72 -0
- package/scripts/sync-paper-artifacts.mjs +109 -0
- package/scripts/verify-arxiv-compile.mjs +440 -0
- package/scripts/verify-arxiv-source.mjs +194 -0
- package/scripts/verify-browser-launch-plan.mjs +237 -0
- package/scripts/verify-browser-launch-results.mjs +285 -0
- package/scripts/verify-paper-artifacts.mjs +338 -0
- package/scripts/verify-paper-claims.mjs +226 -0
- package/scripts/verify-paper-submission-bundle.mjs +207 -0
- package/scripts/verify-publication-pack.mjs +196 -0
- package/scripts/verify-python-package.py +201 -0
- package/scripts/verify-release-readiness.mjs +741 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { join, relative, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { validateSchema } from '../benchmarks/validate-guardbench-artifacts.mjs';
|
|
6
|
+
import { publicPath, scanFilesForLocalPaths } from '../benchmarks/public-paths.mjs';
|
|
7
|
+
|
|
8
|
+
const ROOT = resolve(fileURLToPath(new URL('..', import.meta.url)));
|
|
9
|
+
const DEFAULT_DIR = 'docs/paper/output/submission-bundle';
|
|
10
|
+
const DEFAULT_SCHEMA = 'docs/paper/paper-submission-bundle.schema.json';
|
|
11
|
+
const REQUIRED_FILES = [
|
|
12
|
+
'README.md',
|
|
13
|
+
'LICENSE',
|
|
14
|
+
'package.json',
|
|
15
|
+
'docs/paper/arxiv-compile-report.schema.json',
|
|
16
|
+
'docs/paper/output/arxiv/main.tex',
|
|
17
|
+
'docs/paper/output/arxiv/references.bib',
|
|
18
|
+
'docs/paper/output/arxiv/arxiv-manifest.json',
|
|
19
|
+
'docs/paper/output/arxiv-compile-report.json',
|
|
20
|
+
'docs/paper/audrey-paper-v1.md',
|
|
21
|
+
'docs/paper/browser-launch-plan.json',
|
|
22
|
+
'docs/paper/browser-launch-plan.schema.json',
|
|
23
|
+
'docs/paper/browser-launch-results.json',
|
|
24
|
+
'docs/paper/browser-launch-results.schema.json',
|
|
25
|
+
'docs/paper/claim-register.json',
|
|
26
|
+
'docs/paper/publication-pack.json',
|
|
27
|
+
'docs/paper/evidence-ledger.md',
|
|
28
|
+
'docs/paper/references.bib',
|
|
29
|
+
'docs/paper/SUBMISSION_README.md',
|
|
30
|
+
'benchmarks/output/guardbench-summary.json',
|
|
31
|
+
'benchmarks/output/guardbench-raw.json',
|
|
32
|
+
'benchmarks/output/external/guardbench-external-evidence.json',
|
|
33
|
+
'benchmarks/output/submission-bundle/submission-manifest.json',
|
|
34
|
+
];
|
|
35
|
+
const PASSED_COMPILE_FILES = [
|
|
36
|
+
'docs/paper/output/arxiv-compile/main.pdf',
|
|
37
|
+
'docs/paper/output/arxiv-compile/arxiv-compile.log',
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
function fromRoot(path) {
|
|
41
|
+
return resolve(ROOT, path);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function readJson(path) {
|
|
45
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function sha256File(path) {
|
|
49
|
+
return createHash('sha256').update(readFileSync(path)).digest('hex');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function walkFiles(dir, root = dir) {
|
|
53
|
+
return readdirSync(dir, { withFileTypes: true }).flatMap(entry => {
|
|
54
|
+
const path = join(dir, entry.name);
|
|
55
|
+
if (entry.isDirectory()) return walkFiles(path, root);
|
|
56
|
+
return relative(root, path).replaceAll('\\', '/');
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
61
|
+
const args = {
|
|
62
|
+
dir: DEFAULT_DIR,
|
|
63
|
+
schema: DEFAULT_SCHEMA,
|
|
64
|
+
checkSourceFreshness: true,
|
|
65
|
+
json: false,
|
|
66
|
+
};
|
|
67
|
+
for (let i = 0; i < argv.length; i++) {
|
|
68
|
+
const token = argv[i];
|
|
69
|
+
if ((token === '--dir' || token === '--bundle-dir') && argv[i + 1]) args.dir = argv[++i];
|
|
70
|
+
else if (token === '--schema' && argv[i + 1]) args.schema = argv[++i];
|
|
71
|
+
else if (token === '--no-source-check') args.checkSourceFreshness = false;
|
|
72
|
+
else if (token === '--json') args.json = true;
|
|
73
|
+
else if (token === '--help' || token === '-h') args.help = true;
|
|
74
|
+
else throw new Error(`Unknown argument: ${token}`);
|
|
75
|
+
}
|
|
76
|
+
return args;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function usage() {
|
|
80
|
+
return `Usage: node scripts/verify-paper-submission-bundle.mjs [options]
|
|
81
|
+
|
|
82
|
+
Options:
|
|
83
|
+
--dir <path> Paper submission bundle directory. Default: ${DEFAULT_DIR}.
|
|
84
|
+
--schema <path> Bundle manifest schema. Default: ${DEFAULT_SCHEMA}.
|
|
85
|
+
--no-source-check
|
|
86
|
+
Skip checking bundled hashes against current source files.
|
|
87
|
+
--json Print the machine-readable verification report.
|
|
88
|
+
`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function verifyPaperSubmissionBundle(options = {}) {
|
|
92
|
+
const dir = fromRoot(options.dir ?? DEFAULT_DIR);
|
|
93
|
+
const schemaPath = fromRoot(options.schema ?? DEFAULT_SCHEMA);
|
|
94
|
+
const checkSourceFreshness = options.checkSourceFreshness !== false;
|
|
95
|
+
const manifestPath = join(dir, 'paper-submission-manifest.json');
|
|
96
|
+
const failures = [];
|
|
97
|
+
let manifest = null;
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
manifest = readJson(manifestPath);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
dir,
|
|
105
|
+
files: [],
|
|
106
|
+
failures: [`paper-submission-manifest.json: ${error.message}`],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const schema = readJson(schemaPath);
|
|
112
|
+
failures.push(...validateSchema(manifest, schema, 'audrey-paper-submission-bundle'));
|
|
113
|
+
} catch (error) {
|
|
114
|
+
failures.push(`schema: ${error.message}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const listed = new Map((manifest.files ?? []).map(file => [file.path, file]));
|
|
118
|
+
for (const file of REQUIRED_FILES) {
|
|
119
|
+
if (!listed.has(file)) failures.push(`paper-submission-manifest.json: missing required file record ${file}`);
|
|
120
|
+
}
|
|
121
|
+
const compileReport = listed.has('docs/paper/output/arxiv-compile-report.json')
|
|
122
|
+
? readJson(join(dir, 'docs/paper/output/arxiv-compile-report.json'))
|
|
123
|
+
: null;
|
|
124
|
+
if (compileReport?.status === 'passed') {
|
|
125
|
+
for (const file of PASSED_COMPILE_FILES) {
|
|
126
|
+
if (!listed.has(file)) failures.push(`paper-submission-manifest.json: missing compile-proof file record ${file}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (listed.has('paper-submission-manifest.json')) {
|
|
130
|
+
failures.push('paper-submission-manifest.json: must not include a self-hash file record');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (const [file, record] of listed) {
|
|
134
|
+
const path = join(dir, file);
|
|
135
|
+
if (!existsSync(path)) {
|
|
136
|
+
failures.push(`${file}: listed in manifest but missing from bundle`);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const bytes = readFileSync(path).byteLength;
|
|
140
|
+
if (record.bytes !== bytes) failures.push(`${file}: byte length mismatch`);
|
|
141
|
+
const sha256 = sha256File(path);
|
|
142
|
+
if (record.sha256 !== sha256) failures.push(`${file}: sha256 mismatch`);
|
|
143
|
+
if (checkSourceFreshness && record.source) {
|
|
144
|
+
const sourcePath = fromRoot(record.source);
|
|
145
|
+
if (existsSync(sourcePath)) {
|
|
146
|
+
const sourceBytes = readFileSync(sourcePath).byteLength;
|
|
147
|
+
const sourceSha256 = sha256File(sourcePath);
|
|
148
|
+
if (record.bytes !== sourceBytes || record.sha256 !== sourceSha256) {
|
|
149
|
+
failures.push(`${file}: source file has changed since bundle creation`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const actualFiles = walkFiles(dir).filter(file => file !== 'paper-submission-manifest.json').sort();
|
|
156
|
+
const listedFiles = [...listed.keys()].sort();
|
|
157
|
+
const actualSet = new Set(actualFiles);
|
|
158
|
+
const listedSet = new Set(listedFiles);
|
|
159
|
+
for (const file of actualFiles) {
|
|
160
|
+
if (!listedSet.has(file)) failures.push(`${file}: present in bundle but missing from manifest`);
|
|
161
|
+
}
|
|
162
|
+
for (const file of listedFiles) {
|
|
163
|
+
if (!actualSet.has(file)) failures.push(`${file}: listed in manifest but not present in bundle`);
|
|
164
|
+
}
|
|
165
|
+
for (const file of scanFilesForLocalPaths(dir, actualFiles)) {
|
|
166
|
+
failures.push(`${file}: contains a local absolute path`);
|
|
167
|
+
}
|
|
168
|
+
if (manifest.claimVerification?.ok !== true) failures.push('paper-submission-manifest.json: claimVerification is not ok');
|
|
169
|
+
if (manifest.publicationPackVerification?.ok !== true) failures.push('paper-submission-manifest.json: publicationPackVerification is not ok');
|
|
170
|
+
if (manifest.guardBenchSnapshot?.passed !== 10) failures.push('paper-submission-manifest.json: GuardBench passed count is not 10');
|
|
171
|
+
if (manifest.guardBenchSnapshot?.scenarios !== 10) failures.push('paper-submission-manifest.json: GuardBench scenario count is not 10');
|
|
172
|
+
if (manifest.guardBenchSnapshot?.redactionLeaks !== 0) failures.push('paper-submission-manifest.json: GuardBench decision redaction leaks are not 0');
|
|
173
|
+
if (manifest.guardBenchSnapshot?.artifactLeaks !== 0) failures.push('paper-submission-manifest.json: GuardBench artifact leaks are not 0');
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
ok: failures.length === 0,
|
|
177
|
+
dir: publicPath(dir),
|
|
178
|
+
manifestPath: publicPath(manifestPath),
|
|
179
|
+
files: listedFiles,
|
|
180
|
+
failures,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function main() {
|
|
185
|
+
const args = parseArgs();
|
|
186
|
+
if (args.help) {
|
|
187
|
+
console.log(usage());
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const report = verifyPaperSubmissionBundle(args);
|
|
192
|
+
if (args.json) console.log(JSON.stringify(report, null, 2));
|
|
193
|
+
else if (report.ok) console.log(`Paper submission bundle verification passed: ${report.dir}`);
|
|
194
|
+
else {
|
|
195
|
+
console.error('Paper submission bundle verification failed:');
|
|
196
|
+
for (const failure of report.failures) console.error(`- ${failure}`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (!report.ok) process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
203
|
+
main().catch(error => {
|
|
204
|
+
console.error(error.stack ?? error.message);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { publicPath } from '../benchmarks/public-paths.mjs';
|
|
5
|
+
import { validateSchema } from '../benchmarks/validate-guardbench-artifacts.mjs';
|
|
6
|
+
import { verifyPaperClaims } from './verify-paper-claims.mjs';
|
|
7
|
+
|
|
8
|
+
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
+
const DEFAULT_PACK = 'docs/paper/publication-pack.json';
|
|
10
|
+
const DEFAULT_SCHEMA = 'docs/paper/publication-pack.schema.json';
|
|
11
|
+
const SEEDED_SECRET = 'sk-guardbench-secret-0000000000000000000000000000';
|
|
12
|
+
const REQUIRED_ENTRIES = [
|
|
13
|
+
'arxiv-title',
|
|
14
|
+
'arxiv-abstract',
|
|
15
|
+
'hacker-news-title',
|
|
16
|
+
'hacker-news-comment',
|
|
17
|
+
'reddit-title',
|
|
18
|
+
'reddit-body',
|
|
19
|
+
'x-post-1',
|
|
20
|
+
'x-post-2',
|
|
21
|
+
'linkedin-post',
|
|
22
|
+
];
|
|
23
|
+
const X_URL_RESERVED_CHARS = 24;
|
|
24
|
+
|
|
25
|
+
function fromRoot(path) {
|
|
26
|
+
return resolve(ROOT, path);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function readText(path) {
|
|
30
|
+
const absolute = fromRoot(path);
|
|
31
|
+
if (!existsSync(absolute)) throw new Error(`Missing required file: ${path}`);
|
|
32
|
+
return readFileSync(absolute, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readJson(path) {
|
|
36
|
+
return JSON.parse(readText(path));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
40
|
+
const args = {
|
|
41
|
+
pack: DEFAULT_PACK,
|
|
42
|
+
schema: DEFAULT_SCHEMA,
|
|
43
|
+
json: false,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
for (let i = 0; i < argv.length; i++) {
|
|
47
|
+
const token = argv[i];
|
|
48
|
+
if (token === '--pack' && argv[i + 1]) args.pack = argv[++i];
|
|
49
|
+
else if (token === '--schema' && argv[i + 1]) args.schema = argv[++i];
|
|
50
|
+
else if (token === '--json') args.json = true;
|
|
51
|
+
else if (token === '--help' || token === '-h') args.help = true;
|
|
52
|
+
else throw new Error(`Unknown argument: ${token}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return args;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function usage() {
|
|
59
|
+
return `Usage: node scripts/verify-publication-pack.mjs [options]
|
|
60
|
+
|
|
61
|
+
Options:
|
|
62
|
+
--pack <path> Publication pack JSON. Default: ${DEFAULT_PACK}.
|
|
63
|
+
--schema <path> Publication pack schema. Default: ${DEFAULT_SCHEMA}.
|
|
64
|
+
--json Print the machine-readable verification report.
|
|
65
|
+
`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function referencesPendingClaim(entry, claimMap) {
|
|
69
|
+
return entry.claimIds.some(id => claimMap.get(id)?.status === 'pending');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function hasPendingBoundaryLanguage(text) {
|
|
73
|
+
return /\b(pending|deferred|does not report|not reporting|not claimed|Stage-B|live credentialed)\b/i.test(text);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function validateEntry(entry, claimMap, forbiddenNeedles) {
|
|
77
|
+
const failures = [];
|
|
78
|
+
const reservedUrlChars = Number.isInteger(entry.reservedUrlChars) ? entry.reservedUrlChars : 0;
|
|
79
|
+
if (entry.text.length > entry.maxChars) {
|
|
80
|
+
failures.push(`${entry.id}: text length ${entry.text.length} exceeds maxChars ${entry.maxChars}`);
|
|
81
|
+
}
|
|
82
|
+
if (entry.text.includes(SEEDED_SECRET)) failures.push(`${entry.id}: contains seeded raw secret`);
|
|
83
|
+
if (entry.text.includes('runtime-key')) failures.push(`${entry.id}: contains runtime-key test credential`);
|
|
84
|
+
for (const claimId of entry.claimIds) {
|
|
85
|
+
if (!claimMap.has(claimId)) failures.push(`${entry.id}: unknown claim id ${claimId}`);
|
|
86
|
+
}
|
|
87
|
+
for (const needle of forbiddenNeedles) {
|
|
88
|
+
if (entry.text.includes(needle)) failures.push(`${entry.id}: contains forbidden claim text: ${needle}`);
|
|
89
|
+
}
|
|
90
|
+
if (referencesPendingClaim(entry, claimMap) && !hasPendingBoundaryLanguage(entry.text)) {
|
|
91
|
+
failures.push(`${entry.id}: references a pending claim without explicit pending/deferred boundary language`);
|
|
92
|
+
}
|
|
93
|
+
if (/10\/10/.test(entry.text) && !/\b(local|Stage-A)\b/i.test(entry.text)) {
|
|
94
|
+
failures.push(`${entry.id}: 10/10 claim must be scoped as local or Stage-A`);
|
|
95
|
+
}
|
|
96
|
+
if (/\b(Mem0|Zep)\b/.test(entry.text) && !hasPendingBoundaryLanguage(entry.text)) {
|
|
97
|
+
failures.push(`${entry.id}: Mem0/Zep mention must include pending/deferred boundary language`);
|
|
98
|
+
}
|
|
99
|
+
if (entry.platform === 'hacker-news' && entry.kind === 'title' && entry.text.length > 80) {
|
|
100
|
+
failures.push(`${entry.id}: Hacker News title should stay at or below 80 characters`);
|
|
101
|
+
}
|
|
102
|
+
if (entry.platform === 'x' && entry.text.length > 280) {
|
|
103
|
+
failures.push(`${entry.id}: X post should stay at or below 280 characters`);
|
|
104
|
+
}
|
|
105
|
+
if (entry.platform === 'x' && entry.requiresArtifactUrl === true) {
|
|
106
|
+
if (!Number.isInteger(entry.reservedUrlChars)) {
|
|
107
|
+
failures.push(`${entry.id}: X post requiring an artifact URL must set reservedUrlChars`);
|
|
108
|
+
} else if (entry.reservedUrlChars < X_URL_RESERVED_CHARS) {
|
|
109
|
+
failures.push(`${entry.id}: X artifact URL reserve must be at least ${X_URL_RESERVED_CHARS} characters`);
|
|
110
|
+
}
|
|
111
|
+
if (entry.text.length + reservedUrlChars > entry.maxChars) {
|
|
112
|
+
failures.push(`${entry.id}: text length ${entry.text.length} plus URL reserve ${reservedUrlChars} exceeds maxChars ${entry.maxChars}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return failures;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function verifyPublicationPack(options = {}) {
|
|
119
|
+
const pack = readJson(options.pack ?? DEFAULT_PACK);
|
|
120
|
+
const schema = readJson(options.schema ?? DEFAULT_SCHEMA);
|
|
121
|
+
const claimReport = await verifyPaperClaims();
|
|
122
|
+
const claimRegister = readJson(pack.claimRegister);
|
|
123
|
+
const claimMap = new Map((claimRegister.claims ?? []).map(claim => [claim.id, claim]));
|
|
124
|
+
const forbiddenNeedles = (claimRegister.claims ?? []).flatMap(claim =>
|
|
125
|
+
(claim.forbiddenText ?? []).map(needle => needle.text));
|
|
126
|
+
|
|
127
|
+
const schemaFailures = validateSchema(pack, schema, 'audrey-publication-pack');
|
|
128
|
+
const ids = new Set();
|
|
129
|
+
const entryReports = [];
|
|
130
|
+
const failures = [...schemaFailures.map(failure => `publication pack schema: ${failure}`)];
|
|
131
|
+
|
|
132
|
+
if (!claimReport.ok) failures.push(...claimReport.failures.map(failure => `claim verifier: ${failure}`));
|
|
133
|
+
|
|
134
|
+
for (const entry of pack.entries ?? []) {
|
|
135
|
+
const entryFailures = [];
|
|
136
|
+
const reservedUrlChars = Number.isInteger(entry.reservedUrlChars) ? entry.reservedUrlChars : 0;
|
|
137
|
+
if (ids.has(entry.id)) entryFailures.push(`${entry.id}: duplicate entry id`);
|
|
138
|
+
ids.add(entry.id);
|
|
139
|
+
entryFailures.push(...validateEntry(entry, claimMap, forbiddenNeedles));
|
|
140
|
+
entryReports.push({
|
|
141
|
+
id: entry.id,
|
|
142
|
+
platform: entry.platform,
|
|
143
|
+
kind: entry.kind,
|
|
144
|
+
chars: entry.text.length,
|
|
145
|
+
maxChars: entry.maxChars,
|
|
146
|
+
requiresArtifactUrl: entry.requiresArtifactUrl === true,
|
|
147
|
+
reservedUrlChars,
|
|
148
|
+
effectiveChars: entry.text.length + reservedUrlChars,
|
|
149
|
+
claimIds: entry.claimIds,
|
|
150
|
+
ok: entryFailures.length === 0,
|
|
151
|
+
failures: entryFailures,
|
|
152
|
+
});
|
|
153
|
+
failures.push(...entryFailures);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
for (const id of REQUIRED_ENTRIES) {
|
|
157
|
+
if (!ids.has(id)) failures.push(`Missing required publication-pack entry: ${id}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
schemaVersion: '1.0.0',
|
|
162
|
+
suite: 'Audrey publication pack verification',
|
|
163
|
+
generatedAt: new Date().toISOString(),
|
|
164
|
+
ok: failures.length === 0,
|
|
165
|
+
pack: publicPath(fromRoot(options.pack ?? DEFAULT_PACK)),
|
|
166
|
+
entries: entryReports,
|
|
167
|
+
failures,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function main() {
|
|
172
|
+
const args = parseArgs();
|
|
173
|
+
if (args.help) {
|
|
174
|
+
console.log(usage());
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const report = await verifyPublicationPack(args);
|
|
179
|
+
if (args.json) {
|
|
180
|
+
console.log(JSON.stringify(report, null, 2));
|
|
181
|
+
} else if (report.ok) {
|
|
182
|
+
console.log(`Publication pack verification passed: ${report.entries.length} entry(s)`);
|
|
183
|
+
} else {
|
|
184
|
+
console.error('Publication pack verification failed:');
|
|
185
|
+
for (const failure of report.failures) console.error(`- ${failure}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (!report.ok) process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
192
|
+
main().catch(error => {
|
|
193
|
+
console.error(error.stack ?? error.message);
|
|
194
|
+
process.exit(1);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
import tarfile
|
|
7
|
+
import zipfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
ROOT = Path.cwd()
|
|
12
|
+
PYTHON_ROOT = ROOT / "python"
|
|
13
|
+
DIST = PYTHON_ROOT / "dist"
|
|
14
|
+
LOCAL_PATH_RE = re.compile(r"(?<![A-Za-z])(?:[A-Za-z]:[\\/]|file://|\\\\\?\\)")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def read_text(path):
|
|
18
|
+
return path.read_text(encoding="utf-8")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def package_version():
|
|
22
|
+
text = read_text(PYTHON_ROOT / "audrey_memory" / "_version.py")
|
|
23
|
+
match = re.search(r'__version__\s*=\s*"([^"]+)"', text)
|
|
24
|
+
if not match:
|
|
25
|
+
raise RuntimeError("python/audrey_memory/_version.py is missing __version__")
|
|
26
|
+
return match.group(1)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def pyproject_name():
|
|
30
|
+
text = read_text(PYTHON_ROOT / "pyproject.toml")
|
|
31
|
+
match = re.search(r'^name\s*=\s*"([^"]+)"', text, re.MULTILINE)
|
|
32
|
+
if not match:
|
|
33
|
+
raise RuntimeError("python/pyproject.toml is missing project name")
|
|
34
|
+
return match.group(1)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def metadata_value(text, key):
|
|
38
|
+
match = re.search(rf"^{re.escape(key)}:\s*(.+)$", text, re.MULTILINE)
|
|
39
|
+
return match.group(1).strip() if match else None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def metadata_values(text, key):
|
|
43
|
+
return re.findall(rf"^{re.escape(key)}:\s*(.+)$", text, re.MULTILINE)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def ensure(condition, message, failures):
|
|
47
|
+
if not condition:
|
|
48
|
+
failures.append(message)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def check_local_paths(label, values, failures):
|
|
52
|
+
for value in values:
|
|
53
|
+
if LOCAL_PATH_RE.search(value):
|
|
54
|
+
failures.append(f"{label} contains local absolute path: {value}")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def wheel_metadata(wheel_path, version, failures):
|
|
58
|
+
expected = {
|
|
59
|
+
"audrey_memory/__init__.py",
|
|
60
|
+
"audrey_memory/_version.py",
|
|
61
|
+
"audrey_memory/client.py",
|
|
62
|
+
"audrey_memory/types.py",
|
|
63
|
+
"audrey_memory/py.typed",
|
|
64
|
+
f"audrey_memory-{version}.dist-info/METADATA",
|
|
65
|
+
f"audrey_memory-{version}.dist-info/WHEEL",
|
|
66
|
+
f"audrey_memory-{version}.dist-info/RECORD",
|
|
67
|
+
}
|
|
68
|
+
with zipfile.ZipFile(wheel_path) as wheel:
|
|
69
|
+
names = set(wheel.namelist())
|
|
70
|
+
metadata = wheel.read(f"audrey_memory-{version}.dist-info/METADATA").decode("utf-8")
|
|
71
|
+
wheel_info = wheel.read(f"audrey_memory-{version}.dist-info/WHEEL").decode("utf-8")
|
|
72
|
+
|
|
73
|
+
missing = sorted(expected - names)
|
|
74
|
+
ensure(not missing, f"wheel is missing expected files: {', '.join(missing)}", failures)
|
|
75
|
+
check_local_paths("wheel filename", names, failures)
|
|
76
|
+
check_local_paths("wheel metadata", [metadata, wheel_info], failures)
|
|
77
|
+
return metadata, wheel_info, sorted(names)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def sdist_metadata(sdist_path, version, failures):
|
|
81
|
+
prefix = f"audrey_memory-{version}/"
|
|
82
|
+
expected = {
|
|
83
|
+
f"{prefix}README.md",
|
|
84
|
+
f"{prefix}pyproject.toml",
|
|
85
|
+
f"{prefix}audrey_memory/__init__.py",
|
|
86
|
+
f"{prefix}audrey_memory/_version.py",
|
|
87
|
+
f"{prefix}audrey_memory/client.py",
|
|
88
|
+
f"{prefix}audrey_memory/types.py",
|
|
89
|
+
f"{prefix}audrey_memory/py.typed",
|
|
90
|
+
f"{prefix}audrey_memory.egg-info/PKG-INFO",
|
|
91
|
+
}
|
|
92
|
+
with tarfile.open(sdist_path, "r:gz") as sdist:
|
|
93
|
+
names = set(sdist.getnames())
|
|
94
|
+
pkg_info_file = sdist.extractfile(f"{prefix}audrey_memory.egg-info/PKG-INFO")
|
|
95
|
+
if pkg_info_file is None:
|
|
96
|
+
raise RuntimeError("sdist is missing PKG-INFO")
|
|
97
|
+
pkg_info = pkg_info_file.read().decode("utf-8")
|
|
98
|
+
|
|
99
|
+
missing = sorted(expected - names)
|
|
100
|
+
ensure(not missing, f"sdist is missing expected files: {', '.join(missing)}", failures)
|
|
101
|
+
check_local_paths("sdist filename", names, failures)
|
|
102
|
+
check_local_paths("sdist metadata", [pkg_info], failures)
|
|
103
|
+
return pkg_info, sorted(names)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def check_metadata(label, text, name, version, failures):
|
|
107
|
+
ensure(metadata_value(text, "Name") == name, f"{label} Name is not {name}", failures)
|
|
108
|
+
ensure(metadata_value(text, "Version") == version, f"{label} Version is not {version}", failures)
|
|
109
|
+
ensure(metadata_value(text, "Requires-Python") == ">=3.9", f"{label} Requires-Python is not >=3.9", failures)
|
|
110
|
+
requires = metadata_values(text, "Requires-Dist")
|
|
111
|
+
ensure(any(value.startswith("httpx") for value in requires), f"{label} is missing httpx dependency", failures)
|
|
112
|
+
ensure(any(value.startswith("pydantic") for value in requires), f"{label} is missing pydantic dependency", failures)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def twine_check(paths):
|
|
116
|
+
command = [sys.executable, "-m", "twine", "check", *[str(path) for path in paths]]
|
|
117
|
+
return subprocess.run(command, cwd=ROOT, capture_output=True, text=True)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def public_path(path):
|
|
121
|
+
try:
|
|
122
|
+
return path.relative_to(ROOT).as_posix()
|
|
123
|
+
except ValueError:
|
|
124
|
+
return path.as_posix()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def public_output(text):
|
|
128
|
+
if not text:
|
|
129
|
+
return ""
|
|
130
|
+
return text.replace(str(ROOT), ".").replace(ROOT.as_posix(), ".")
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def verify(version=None, skip_twine=False):
|
|
134
|
+
version = version or package_version()
|
|
135
|
+
name = pyproject_name()
|
|
136
|
+
wheel_path = DIST / f"audrey_memory-{version}-py3-none-any.whl"
|
|
137
|
+
sdist_path = DIST / f"audrey_memory-{version}.tar.gz"
|
|
138
|
+
failures = []
|
|
139
|
+
|
|
140
|
+
ensure(wheel_path.exists(), f"missing wheel: {wheel_path.as_posix()}", failures)
|
|
141
|
+
ensure(sdist_path.exists(), f"missing sdist: {sdist_path.as_posix()}", failures)
|
|
142
|
+
|
|
143
|
+
wheel_files = []
|
|
144
|
+
sdist_files = []
|
|
145
|
+
if wheel_path.exists():
|
|
146
|
+
wheel_meta, _wheel_info, wheel_files = wheel_metadata(wheel_path, version, failures)
|
|
147
|
+
check_metadata("wheel METADATA", wheel_meta, name, version, failures)
|
|
148
|
+
if sdist_path.exists():
|
|
149
|
+
sdist_meta, sdist_files = sdist_metadata(sdist_path, version, failures)
|
|
150
|
+
check_metadata("sdist PKG-INFO", sdist_meta, name, version, failures)
|
|
151
|
+
|
|
152
|
+
twine = None
|
|
153
|
+
if not skip_twine and wheel_path.exists() and sdist_path.exists():
|
|
154
|
+
result = twine_check([wheel_path, sdist_path])
|
|
155
|
+
twine = {
|
|
156
|
+
"ok": result.returncode == 0,
|
|
157
|
+
"stdout": public_output(result.stdout.strip()),
|
|
158
|
+
"stderr": public_output(result.stderr.strip()),
|
|
159
|
+
}
|
|
160
|
+
if result.returncode != 0:
|
|
161
|
+
failures.append(f"twine check failed: {result.stderr.strip() or result.stdout.strip()}")
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
"schemaVersion": "1.0.0",
|
|
165
|
+
"suite": "Audrey Python package verification",
|
|
166
|
+
"ok": not failures,
|
|
167
|
+
"packageName": name,
|
|
168
|
+
"version": version,
|
|
169
|
+
"wheel": public_path(wheel_path),
|
|
170
|
+
"sdist": public_path(sdist_path),
|
|
171
|
+
"wheelFiles": wheel_files,
|
|
172
|
+
"sdistFiles": sdist_files,
|
|
173
|
+
"twine": twine,
|
|
174
|
+
"failures": failures,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def main():
|
|
179
|
+
parser = argparse.ArgumentParser(description="Verify Audrey Python wheel/sdist release artifacts.")
|
|
180
|
+
parser.add_argument("--version", default=None)
|
|
181
|
+
parser.add_argument("--skip-twine", action="store_true")
|
|
182
|
+
parser.add_argument("--json", action="store_true")
|
|
183
|
+
args = parser.parse_args()
|
|
184
|
+
|
|
185
|
+
report = verify(version=args.version, skip_twine=args.skip_twine)
|
|
186
|
+
if args.json:
|
|
187
|
+
print(json.dumps(report, indent=2))
|
|
188
|
+
elif report["ok"]:
|
|
189
|
+
twine_status = "twine skipped" if report["twine"] is None else "twine passed"
|
|
190
|
+
print(f"Python package verification passed: {report['packageName']} {report['version']} ({twine_status})")
|
|
191
|
+
else:
|
|
192
|
+
print("Python package verification failed:", file=sys.stderr)
|
|
193
|
+
for failure in report["failures"]:
|
|
194
|
+
print(f"- {failure}", file=sys.stderr)
|
|
195
|
+
|
|
196
|
+
if not report["ok"]:
|
|
197
|
+
raise SystemExit(1)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
if __name__ == "__main__":
|
|
201
|
+
main()
|