audrey 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +30 -6
  3. package/benchmarks/adapter-self-test.mjs +6 -2
  4. package/benchmarks/adapters/example-allow.mjs +5 -2
  5. package/benchmarks/adapters/mem0-platform.mjs +19 -12
  6. package/benchmarks/adapters/zep-cloud.mjs +51 -27
  7. package/benchmarks/baselines.js +11 -6
  8. package/benchmarks/build-leaderboard.mjs +36 -23
  9. package/benchmarks/cases.js +24 -12
  10. package/benchmarks/create-conformance-card.mjs +12 -3
  11. package/benchmarks/create-submission-bundle.mjs +22 -8
  12. package/benchmarks/dry-run-external-adapters.mjs +24 -12
  13. package/benchmarks/guardbench.js +354 -124
  14. package/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +7 -7
  15. package/benchmarks/output/external/guardbench-external-dry-run.json +1 -1
  16. package/benchmarks/output/external/guardbench-external-evidence.json +1 -1
  17. package/benchmarks/output/guardbench-conformance-card.json +12 -12
  18. package/benchmarks/output/guardbench-raw.json +243 -144
  19. package/benchmarks/output/guardbench-summary.json +354 -230
  20. package/benchmarks/output/leaderboard/guardbench-leaderboard.json +5 -5
  21. package/benchmarks/output/leaderboard/guardbench-leaderboard.md +2 -2
  22. package/benchmarks/output/submission-bundle/guardbench-conformance-card.json +12 -12
  23. package/benchmarks/output/submission-bundle/guardbench-raw.json +243 -144
  24. package/benchmarks/output/submission-bundle/guardbench-summary.json +354 -230
  25. package/benchmarks/output/submission-bundle/schemas/guardbench-raw.schema.json +21 -1
  26. package/benchmarks/output/submission-bundle/schemas/guardbench-summary.schema.json +23 -2
  27. package/benchmarks/output/submission-bundle/submission-manifest.json +15 -15
  28. package/benchmarks/output/submission-bundle/validation-report.json +1 -1
  29. package/benchmarks/output/summary.json +58 -58
  30. package/benchmarks/perf-snapshot.js +12 -9
  31. package/benchmarks/perf.bench.js +14 -6
  32. package/benchmarks/public-paths.mjs +11 -5
  33. package/benchmarks/reference-results.js +10 -5
  34. package/benchmarks/report.js +48 -27
  35. package/benchmarks/run-external-guardbench.mjs +47 -25
  36. package/benchmarks/run.js +112 -59
  37. package/benchmarks/schemas/guardbench-raw.schema.json +21 -1
  38. package/benchmarks/schemas/guardbench-summary.schema.json +23 -2
  39. package/benchmarks/validate-adapter-module.mjs +13 -10
  40. package/benchmarks/validate-adapter-registry.mjs +16 -5
  41. package/benchmarks/validate-guardbench-artifacts.mjs +76 -19
  42. package/benchmarks/verify-external-evidence.mjs +86 -31
  43. package/benchmarks/verify-publication-artifacts.mjs +34 -11
  44. package/benchmarks/verify-submission-bundle.mjs +9 -4
  45. package/dist/mcp-server/config.d.ts +1 -1
  46. package/dist/mcp-server/config.d.ts.map +1 -1
  47. package/dist/mcp-server/config.js +5 -3
  48. package/dist/mcp-server/config.js.map +1 -1
  49. package/dist/mcp-server/index.d.ts +4 -3
  50. package/dist/mcp-server/index.d.ts.map +1 -1
  51. package/dist/mcp-server/index.js +479 -172
  52. package/dist/mcp-server/index.js.map +1 -1
  53. package/dist/src/action-key.d.ts.map +1 -1
  54. package/dist/src/action-key.js +6 -2
  55. package/dist/src/action-key.js.map +1 -1
  56. package/dist/src/adaptive.d.ts.map +1 -1
  57. package/dist/src/adaptive.js +4 -2
  58. package/dist/src/adaptive.js.map +1 -1
  59. package/dist/src/affect.d.ts.map +1 -1
  60. package/dist/src/affect.js +8 -5
  61. package/dist/src/affect.js.map +1 -1
  62. package/dist/src/audrey.d.ts +11 -1
  63. package/dist/src/audrey.d.ts.map +1 -1
  64. package/dist/src/audrey.js +110 -53
  65. package/dist/src/audrey.js.map +1 -1
  66. package/dist/src/capsule.d.ts.map +1 -1
  67. package/dist/src/capsule.js +37 -15
  68. package/dist/src/capsule.js.map +1 -1
  69. package/dist/src/causal.d.ts +1 -1
  70. package/dist/src/causal.d.ts.map +1 -1
  71. package/dist/src/causal.js +4 -2
  72. package/dist/src/causal.js.map +1 -1
  73. package/dist/src/confidence.d.ts.map +1 -1
  74. package/dist/src/confidence.js +5 -5
  75. package/dist/src/confidence.js.map +1 -1
  76. package/dist/src/consolidate.d.ts.map +1 -1
  77. package/dist/src/consolidate.js +17 -9
  78. package/dist/src/consolidate.js.map +1 -1
  79. package/dist/src/context.js +1 -1
  80. package/dist/src/context.js.map +1 -1
  81. package/dist/src/controller.d.ts +17 -1
  82. package/dist/src/controller.d.ts.map +1 -1
  83. package/dist/src/controller.js +73 -23
  84. package/dist/src/controller.js.map +1 -1
  85. package/dist/src/db.d.ts.map +1 -1
  86. package/dist/src/db.js +78 -27
  87. package/dist/src/db.js.map +1 -1
  88. package/dist/src/decay.d.ts +1 -1
  89. package/dist/src/decay.d.ts.map +1 -1
  90. package/dist/src/decay.js +1 -1
  91. package/dist/src/decay.js.map +1 -1
  92. package/dist/src/embedding.d.ts +12 -4
  93. package/dist/src/embedding.d.ts.map +1 -1
  94. package/dist/src/embedding.js +18 -16
  95. package/dist/src/embedding.js.map +1 -1
  96. package/dist/src/encode.d.ts.map +1 -1
  97. package/dist/src/encode.js +5 -4
  98. package/dist/src/encode.js.map +1 -1
  99. package/dist/src/events.d.ts +3 -2
  100. package/dist/src/events.d.ts.map +1 -1
  101. package/dist/src/events.js +7 -3
  102. package/dist/src/events.js.map +1 -1
  103. package/dist/src/export.d.ts.map +1 -1
  104. package/dist/src/export.js +21 -7
  105. package/dist/src/export.js.map +1 -1
  106. package/dist/src/feedback.d.ts.map +1 -1
  107. package/dist/src/feedback.js +1 -1
  108. package/dist/src/feedback.js.map +1 -1
  109. package/dist/src/forget.d.ts.map +1 -1
  110. package/dist/src/forget.js +12 -6
  111. package/dist/src/forget.js.map +1 -1
  112. package/dist/src/fts.d.ts.map +1 -1
  113. package/dist/src/fts.js +20 -8
  114. package/dist/src/fts.js.map +1 -1
  115. package/dist/src/hybrid-recall.d.ts.map +1 -1
  116. package/dist/src/hybrid-recall.js +12 -6
  117. package/dist/src/hybrid-recall.js.map +1 -1
  118. package/dist/src/impact.d.ts.map +1 -1
  119. package/dist/src/impact.js +26 -10
  120. package/dist/src/impact.js.map +1 -1
  121. package/dist/src/import.d.ts.map +1 -1
  122. package/dist/src/import.js +11 -6
  123. package/dist/src/import.js.map +1 -1
  124. package/dist/src/index.d.ts +5 -4
  125. package/dist/src/index.d.ts.map +1 -1
  126. package/dist/src/index.js +4 -4
  127. package/dist/src/index.js.map +1 -1
  128. package/dist/src/interference.d.ts.map +1 -1
  129. package/dist/src/interference.js +10 -5
  130. package/dist/src/interference.js.map +1 -1
  131. package/dist/src/introspect.d.ts.map +1 -1
  132. package/dist/src/introspect.js +12 -6
  133. package/dist/src/introspect.js.map +1 -1
  134. package/dist/src/llm.d.ts +2 -2
  135. package/dist/src/llm.d.ts.map +1 -1
  136. package/dist/src/llm.js +6 -6
  137. package/dist/src/llm.js.map +1 -1
  138. package/dist/src/migrate.d.ts.map +1 -1
  139. package/dist/src/migrate.js +10 -4
  140. package/dist/src/migrate.js.map +1 -1
  141. package/dist/src/preflight.d.ts.map +1 -1
  142. package/dist/src/preflight.js +6 -8
  143. package/dist/src/preflight.js.map +1 -1
  144. package/dist/src/profile.d.ts.map +1 -1
  145. package/dist/src/profile.js.map +1 -1
  146. package/dist/src/promote.d.ts.map +1 -1
  147. package/dist/src/promote.js +16 -7
  148. package/dist/src/promote.js.map +1 -1
  149. package/dist/src/prompts.d.ts.map +1 -1
  150. package/dist/src/prompts.js +1 -2
  151. package/dist/src/prompts.js.map +1 -1
  152. package/dist/src/recall.d.ts.map +1 -1
  153. package/dist/src/recall.js +85 -18
  154. package/dist/src/recall.js.map +1 -1
  155. package/dist/src/redact.d.ts.map +1 -1
  156. package/dist/src/redact.js +9 -4
  157. package/dist/src/redact.js.map +1 -1
  158. package/dist/src/reflexes.d.ts.map +1 -1
  159. package/dist/src/reflexes.js +1 -7
  160. package/dist/src/reflexes.js.map +1 -1
  161. package/dist/src/rollback.d.ts.map +1 -1
  162. package/dist/src/rollback.js +4 -2
  163. package/dist/src/rollback.js.map +1 -1
  164. package/dist/src/routes.d.ts.map +1 -1
  165. package/dist/src/routes.js +37 -14
  166. package/dist/src/routes.js.map +1 -1
  167. package/dist/src/rules-compiler.d.ts.map +1 -1
  168. package/dist/src/rules-compiler.js +24 -2
  169. package/dist/src/rules-compiler.js.map +1 -1
  170. package/dist/src/server.js +2 -2
  171. package/dist/src/server.js.map +1 -1
  172. package/dist/src/tool-trace.d.ts +2 -2
  173. package/dist/src/tool-trace.d.ts.map +1 -1
  174. package/dist/src/tool-trace.js +12 -4
  175. package/dist/src/tool-trace.js.map +1 -1
  176. package/dist/src/types.d.ts.map +1 -1
  177. package/dist/src/ulid.js +1 -1
  178. package/dist/src/ulid.js.map +1 -1
  179. package/dist/src/utils.d.ts.map +1 -1
  180. package/dist/src/utils.js.map +1 -1
  181. package/dist/src/validate.d.ts.map +1 -1
  182. package/dist/src/validate.js +20 -10
  183. package/dist/src/validate.js.map +1 -1
  184. package/docs/paper/07-evaluation.md +5 -5
  185. package/docs/paper/audrey-paper-v1.md +6 -6
  186. package/docs/paper/evidence-ledger.md +1 -1
  187. package/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
  188. package/docs/paper/output/arxiv/main.tex +6 -6
  189. package/docs/paper/output/arxiv-compile-report.json +3 -3
  190. package/docs/paper/output/submission-bundle/README.md +30 -6
  191. package/docs/paper/output/submission-bundle/benchmarks/output/adapter-self-test/guardbench-adapter-self-test.json +7 -7
  192. package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-dry-run.json +1 -1
  193. package/docs/paper/output/submission-bundle/benchmarks/output/external/guardbench-external-evidence.json +1 -1
  194. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-conformance-card.json +12 -12
  195. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-raw.json +243 -144
  196. package/docs/paper/output/submission-bundle/benchmarks/output/guardbench-summary.json +354 -230
  197. package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.json +5 -5
  198. package/docs/paper/output/submission-bundle/benchmarks/output/leaderboard/guardbench-leaderboard.md +2 -2
  199. package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/submission-manifest.json +15 -15
  200. package/docs/paper/output/submission-bundle/benchmarks/output/submission-bundle/validation-report.json +1 -1
  201. package/docs/paper/output/submission-bundle/benchmarks/output/summary.json +52 -52
  202. package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-raw.schema.json +21 -1
  203. package/docs/paper/output/submission-bundle/benchmarks/schemas/guardbench-summary.schema.json +23 -2
  204. package/docs/paper/output/submission-bundle/docs/paper/07-evaluation.md +5 -5
  205. package/docs/paper/output/submission-bundle/docs/paper/audrey-paper-v1.md +6 -6
  206. package/docs/paper/output/submission-bundle/docs/paper/evidence-ledger.md +1 -1
  207. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/arxiv-manifest.json +4 -4
  208. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv/main.tex +6 -6
  209. package/docs/paper/output/submission-bundle/docs/paper/output/arxiv-compile-report.json +3 -3
  210. package/docs/paper/output/submission-bundle/package.json +18 -5
  211. package/docs/paper/output/submission-bundle/paper-submission-manifest.json +40 -40
  212. package/examples/fintech-ops-demo.js +12 -5
  213. package/examples/healthcare-ops-demo.js +8 -4
  214. package/examples/ollama-memory-agent.js +41 -13
  215. package/examples/stripe-demo.js +12 -5
  216. package/package.json +18 -5
  217. package/scripts/audit-release-completion.mjs +179 -101
  218. package/scripts/create-arxiv-source.mjs +20 -14
  219. package/scripts/create-paper-submission-bundle.mjs +6 -2
  220. package/scripts/finalize-release.mjs +111 -36
  221. package/scripts/prepare-release-cut.mjs +14 -6
  222. package/scripts/publish-release-bundle.mjs +62 -23
  223. package/scripts/publish-release-github-api.mjs +89 -24
  224. package/scripts/smoke-cli.js +26 -6
  225. package/scripts/sync-paper-artifacts.mjs +5 -1
  226. package/scripts/verify-arxiv-compile.mjs +52 -16
  227. package/scripts/verify-arxiv-source.mjs +45 -15
  228. package/scripts/verify-browser-launch-plan.mjs +28 -11
  229. package/scripts/verify-browser-launch-results.mjs +32 -14
  230. package/scripts/verify-paper-artifacts.mjs +539 -79
  231. package/scripts/verify-paper-claims.mjs +48 -20
  232. package/scripts/verify-paper-submission-bundle.mjs +22 -11
  233. package/scripts/verify-publication-pack.mjs +23 -9
  234. package/scripts/verify-release-readiness.mjs +250 -71
@@ -16,6 +16,7 @@ const ROOT = process.cwd();
16
16
  const DEFAULT_TARGET_VERSION = '1.0.0';
17
17
  const PYPI_CREDENTIAL_ENVS = ['TWINE_PASSWORD', 'PYPI_API_TOKEN', 'UV_PUBLISH_TOKEN'];
18
18
  const NPM_REGISTRY = 'https://registry.npmjs.org/';
19
+ const PYPI_JSON_BASE = 'https://pypi.org/pypi';
19
20
 
20
21
  function fromRoot(path) {
21
22
  return resolve(ROOT, path);
@@ -35,13 +36,16 @@ function parseArgs(argv = process.argv.slice(2)) {
35
36
  const args = {
36
37
  targetVersion: DEFAULT_TARGET_VERSION,
37
38
  allowPending: false,
39
+ checkPypiRegistry: true,
38
40
  json: false,
39
41
  };
40
42
 
41
43
  for (let i = 0; i < argv.length; i++) {
42
44
  const token = argv[i];
43
- if ((token === '--target-version' || token === '--version') && argv[i + 1]) args.targetVersion = argv[++i];
45
+ if ((token === '--target-version' || token === '--version') && argv[i + 1])
46
+ args.targetVersion = argv[++i];
44
47
  else if (token === '--allow-pending') args.allowPending = true;
48
+ else if (token === '--skip-pypi-registry') args.checkPypiRegistry = false;
45
49
  else if (token === '--json') args.json = true;
46
50
  else if (token === '--help' || token === '-h') args.help = true;
47
51
  else throw new Error(`Unknown argument: ${token}`);
@@ -56,6 +60,7 @@ function usage() {
56
60
  Options:
57
61
  --target-version <version> Target release version. Default: ${DEFAULT_TARGET_VERSION}.
58
62
  --allow-pending Exit 0 when only publish/account/credential blockers remain.
63
+ --skip-pypi-registry Do not check whether the target PyPI version is already public.
59
64
  --json Print the machine-readable readiness report.
60
65
  `;
61
66
  }
@@ -177,7 +182,10 @@ export function remoteBranchFreshnessStatus({ branch, upstream, upstreamSha }, r
177
182
  const remoteRef = `refs/heads/${branch}`;
178
183
  let result = run(['ls-remote', 'origin', remoteRef]);
179
184
  const fallbackEvidence = [];
180
- if (result.status !== 0 && /schannel|AcquireCredentialsHandle|SEC_E_NO_CREDENTIALS/i.test(commandSummary(result))) {
185
+ if (
186
+ result.status !== 0 &&
187
+ /schannel|AcquireCredentialsHandle|SEC_E_NO_CREDENTIALS/i.test(commandSummary(result))
188
+ ) {
181
189
  const fallback = run(['-c', 'http.sslBackend=openssl', 'ls-remote', 'origin', remoteRef]);
182
190
  if (fallback.status === 0) {
183
191
  result = fallback;
@@ -187,11 +195,16 @@ export function remoteBranchFreshnessStatus({ branch, upstream, upstreamSha }, r
187
195
  if (result.status !== 0) {
188
196
  return {
189
197
  evidence: ['remoteHead=unverified', ...fallbackEvidence],
190
- blockers: [`Verify live remote origin/${branch} before final release (${commandSummary(result)})`],
198
+ blockers: [
199
+ `Verify live remote origin/${branch} before final release (${commandSummary(result)})`,
200
+ ],
191
201
  };
192
202
  }
193
203
 
194
- const remoteLine = result.stdout.trim().split(/\r?\n/).find(line => line.endsWith(remoteRef));
204
+ const remoteLine = result.stdout
205
+ .trim()
206
+ .split(/\r?\n/)
207
+ .find(line => line.endsWith(remoteRef));
195
208
  const remoteSha = remoteLine?.split(/\s+/)[0];
196
209
  if (!remoteSha) {
197
210
  return {
@@ -203,7 +216,9 @@ export function remoteBranchFreshnessStatus({ branch, upstream, upstreamSha }, r
203
216
  const evidence = [...fallbackEvidence, `remoteHead=origin/${branch}:${shortSha(remoteSha)}`];
204
217
  const blockers = [];
205
218
  if (upstream && upstreamSha && upstreamSha !== remoteSha) {
206
- blockers.push(`Fetch/reconcile origin/${branch}: local ${upstream} is ${shortSha(upstreamSha)} but live remote is ${shortSha(remoteSha)}`);
219
+ blockers.push(
220
+ `Fetch/reconcile origin/${branch}: local ${upstream} is ${shortSha(upstreamSha)} but live remote is ${shortSha(remoteSha)}`,
221
+ );
207
222
  }
208
223
 
209
224
  return { evidence, blockers };
@@ -214,8 +229,19 @@ function remoteReleaseRefs(branch, targetVersion, run = runGit) {
214
229
  const tagRef = `refs/tags/v${targetVersion}`;
215
230
  let result = run(['ls-remote', 'origin', branchRef, tagRef, `${tagRef}^{}`]);
216
231
  const evidence = [];
217
- if (result.status !== 0 && /schannel|AcquireCredentialsHandle|SEC_E_NO_CREDENTIALS/i.test(commandSummary(result))) {
218
- const fallback = run(['-c', 'http.sslBackend=openssl', 'ls-remote', 'origin', branchRef, tagRef, `${tagRef}^{}`]);
232
+ if (
233
+ result.status !== 0 &&
234
+ /schannel|AcquireCredentialsHandle|SEC_E_NO_CREDENTIALS/i.test(commandSummary(result))
235
+ ) {
236
+ const fallback = run([
237
+ '-c',
238
+ 'http.sslBackend=openssl',
239
+ 'ls-remote',
240
+ 'origin',
241
+ branchRef,
242
+ tagRef,
243
+ `${tagRef}^{}`,
244
+ ]);
219
245
  if (fallback.status === 0) {
220
246
  result = fallback;
221
247
  evidence.push('releaseRemoteTlsFallback=openssl');
@@ -249,7 +275,10 @@ function currentWorkingReleaseTree() {
249
275
  };
250
276
 
251
277
  try {
252
- for (const args of [['read-tree', 'HEAD'], ['add', '--all']]) {
278
+ for (const args of [
279
+ ['read-tree', 'HEAD'],
280
+ ['add', '--all'],
281
+ ]) {
253
282
  const result = runGit(args, { env, timeout: 120000 });
254
283
  if (result.status !== 0) return { ok: false, error: commandSummary(result) };
255
284
  }
@@ -288,7 +317,9 @@ function releaseSourceHandoffStatus(targetVersion, branch) {
288
317
  } else {
289
318
  evidence.push(`currentReleaseTree=${shortSha(currentTree.tree)}`);
290
319
  if (report.tree && currentTree.tree !== report.tree) {
291
- blockers.push(`Regenerate release artifacts: current release tree ${currentTree.tree} differs from source handoff tree ${report.tree}`);
320
+ blockers.push(
321
+ `Regenerate release artifacts: current release tree ${currentTree.tree} differs from source handoff tree ${report.tree}`,
322
+ );
292
323
  }
293
324
  }
294
325
 
@@ -300,10 +331,14 @@ function releaseSourceHandoffStatus(targetVersion, branch) {
300
331
  evidence.push('sourceBundleVerify=passed');
301
332
  const refs = parseBundleRefs(bundleVerify.stdout, targetVersion);
302
333
  if (refs.branch !== report.commit) {
303
- blockers.push(`Release source bundle master is ${refs.branch ?? 'missing'}, expected ${report.commit}`);
334
+ blockers.push(
335
+ `Release source bundle master is ${refs.branch ?? 'missing'}, expected ${report.commit}`,
336
+ );
304
337
  }
305
338
  if (refs.tag !== report.tag) {
306
- blockers.push(`Release source bundle tag is ${refs.tag ?? 'missing'}, expected ${report.tag}`);
339
+ blockers.push(
340
+ `Release source bundle tag is ${refs.tag ?? 'missing'}, expected ${report.tag}`,
341
+ );
307
342
  }
308
343
  }
309
344
 
@@ -316,13 +351,19 @@ function releaseSourceHandoffStatus(targetVersion, branch) {
316
351
  evidence.push(`releaseRemoteMaster=${shortSha(remoteMaster)}`);
317
352
  evidence.push(`releaseRemoteTag=${shortSha(remoteTagObject)}`);
318
353
  if (report.commit && remoteMaster !== report.commit) {
319
- blockers.push(`Publish source bundle commit ${report.commit} to origin/${branch} (remote is ${remoteMaster ?? 'missing'})`);
354
+ blockers.push(
355
+ `Publish source bundle commit ${report.commit} to origin/${branch} (remote is ${remoteMaster ?? 'missing'})`,
356
+ );
320
357
  }
321
358
  if (report.tag && remoteTagObject !== report.tag) {
322
- blockers.push(`Publish source bundle tag object ${report.tag} to refs/tags/v${targetVersion} (remote is ${remoteTagObject ?? 'missing'})`);
359
+ blockers.push(
360
+ `Publish source bundle tag object ${report.tag} to refs/tags/v${targetVersion} (remote is ${remoteTagObject ?? 'missing'})`,
361
+ );
323
362
  }
324
363
  if (remoteTagCommit && report.commit && remoteTagCommit !== report.commit) {
325
- blockers.push(`Remote v${targetVersion} dereferences to ${remoteTagCommit}, not release commit ${report.commit}`);
364
+ blockers.push(
365
+ `Remote v${targetVersion} dereferences to ${remoteTagCommit}, not release commit ${report.commit}`,
366
+ );
326
367
  }
327
368
 
328
369
  const stalePrefixes = [
@@ -360,18 +401,19 @@ function versionChecks(targetVersion) {
360
401
  const evidence = values.map(([name, value]) => `${name}=${value ?? 'missing'}`);
361
402
 
362
403
  if (values.some(([, value]) => !value)) {
363
- return failed('version-surfaces', 'Version surfaces are present', evidence, ['One or more version surfaces are missing']);
404
+ return failed('version-surfaces', 'Version surfaces are present', evidence, [
405
+ 'One or more version surfaces are missing',
406
+ ]);
364
407
  }
365
408
  if (uniqueVersions.size !== 1) {
366
- return failed('version-surfaces', 'Version surfaces are aligned', evidence, ['package.json, package-lock.json, and Python version are not aligned']);
409
+ return failed('version-surfaces', 'Version surfaces are aligned', evidence, [
410
+ 'package.json, package-lock.json, and Python version are not aligned',
411
+ ]);
367
412
  }
368
413
  if (!uniqueVersions.has(targetVersion)) {
369
- return pending(
370
- 'target-version',
371
- `Target release version is ${targetVersion}`,
372
- evidence,
373
- [`Local version is ${versions.packageJson}; bump all release surfaces to ${targetVersion} only when 1.0 publish is being cut`],
374
- );
414
+ return pending('target-version', `Target release version is ${targetVersion}`, evidence, [
415
+ `Local version is ${versions.packageJson}; bump all release surfaces to ${targetVersion} only when 1.0 publish is being cut`,
416
+ ]);
375
417
  }
376
418
  return ok('target-version', `Target release version is ${targetVersion}`, evidence);
377
419
  }
@@ -379,7 +421,8 @@ function versionChecks(targetVersion) {
379
421
  function sourceControlCheck(targetVersion) {
380
422
  const status = runGit(['status', '--short', '--branch', '--untracked-files=all']);
381
423
  if (status.status !== 0) {
382
- const detail = status.stderr.trim() || status.stdout.trim() || `git status exited ${status.status}`;
424
+ const detail =
425
+ status.stderr.trim() || status.stdout.trim() || `git status exited ${status.status}`;
383
426
  return failed('source-control', 'Source control is ready for release', [], [detail]);
384
427
  }
385
428
 
@@ -393,10 +436,16 @@ function sourceControlCheck(targetVersion) {
393
436
  const originPush = gitOutput(['remote', 'get-url', '--push', 'origin']);
394
437
  const tagName = `v${targetVersion}`;
395
438
  const tagExists = Boolean(gitOutput(['tag', '--list', tagName]));
396
- const tagsAtHead = (gitOutput(['tag', '--points-at', 'HEAD']) ?? '').split(/\r?\n/).filter(Boolean);
439
+ const tagsAtHead = (gitOutput(['tag', '--points-at', 'HEAD']) ?? '')
440
+ .split(/\r?\n/)
441
+ .filter(Boolean);
397
442
  const metadataWritable = gitMetadataWritableCheck();
398
- const remoteFreshness = originPush ? remoteBranchFreshnessStatus({ branch, upstream, upstreamSha }) : { evidence: [], blockers: [] };
399
- const sourceHandoff = originPush ? releaseSourceHandoffStatus(targetVersion, branch) : { usable: false, evidence: [], blockers: [] };
443
+ const remoteFreshness = originPush
444
+ ? remoteBranchFreshnessStatus({ branch, upstream, upstreamSha })
445
+ : { evidence: [], blockers: [] };
446
+ const sourceHandoff = originPush
447
+ ? releaseSourceHandoffStatus(targetVersion, branch)
448
+ : { usable: false, evidence: [], blockers: [] };
400
449
  const evidence = [
401
450
  `branch=${branch}`,
402
451
  `head=${head}`,
@@ -415,7 +464,8 @@ function sourceControlCheck(targetVersion) {
415
464
  blockers.push(...sourceHandoff.blockers);
416
465
  evidence.push('sourceControlLane=external-source-bundle');
417
466
  } else {
418
- if (!metadataWritable.writable && metadataWritable.blocker) blockers.push(metadataWritable.blocker);
467
+ if (!metadataWritable.writable && metadataWritable.blocker)
468
+ blockers.push(metadataWritable.blocker);
419
469
  blockers.push(...remoteFreshness.blockers, ...sourceHandoff.blockers);
420
470
  if (!upstream) blockers.push('Configure an upstream branch before final release');
421
471
  if (upstream) {
@@ -424,18 +474,26 @@ function sourceControlCheck(targetVersion) {
424
474
  const [ahead, behind] = counts.split(/\s+/).map(Number);
425
475
  evidence.push(`ahead=${ahead}`, `behind=${behind}`);
426
476
  if (ahead > 0) blockers.push(`Push ${ahead} release commit(s) to ${upstream}`);
427
- if (behind > 0) blockers.push(`Pull or reconcile ${behind} upstream commit(s) before final release`);
477
+ if (behind > 0)
478
+ blockers.push(`Pull or reconcile ${behind} upstream commit(s) before final release`);
428
479
  }
429
480
  }
430
- if (changedLines.length > 0) blockers.push(`Commit or stash ${changedLines.length} working-tree change(s) before final release`);
481
+ if (changedLines.length > 0)
482
+ blockers.push(
483
+ `Commit or stash ${changedLines.length} working-tree change(s) before final release`,
484
+ );
431
485
  if (!tagExists) blockers.push(`Create release tag ${tagName} on the final release commit`);
432
- if (tagExists && !tagsAtHead.includes(tagName)) blockers.push(`Move or recreate ${tagName} so it points at the final release commit`);
486
+ if (tagExists && !tagsAtHead.includes(tagName))
487
+ blockers.push(`Move or recreate ${tagName} so it points at the final release commit`);
433
488
  }
434
489
 
435
490
  if (blockers.length > 0) {
436
491
  return pending('source-control', 'Source control is ready for release', evidence, blockers);
437
492
  }
438
- return ok('source-control', 'Source control is ready for release', [...evidence, `${tagName} points at HEAD`]);
493
+ return ok('source-control', 'Source control is ready for release', [
494
+ ...evidence,
495
+ `${tagName} points at HEAD`,
496
+ ]);
439
497
  }
440
498
 
441
499
  function escapeRegex(value) {
@@ -452,7 +510,8 @@ export function targetChangelogStatus(changelog, targetVersion) {
452
510
  const section = nextSection === -1 ? rest : rest.slice(0, nextSection);
453
511
  const placeholderMarkers = [];
454
512
  if (/\bTODO\b/i.test(section)) placeholderMarkers.push('TODO marker');
455
- if (/Release Cut Checklist/i.test(section)) placeholderMarkers.push('release-cut checklist scaffold');
513
+ if (/Release Cut Checklist/i.test(section))
514
+ placeholderMarkers.push('release-cut checklist scaffold');
456
515
 
457
516
  return { found: true, placeholderMarkers };
458
517
  }
@@ -461,14 +520,18 @@ function changelogCheck(targetVersion) {
461
520
  const changelog = readText('CHANGELOG.md');
462
521
  const status = targetChangelogStatus(changelog, targetVersion);
463
522
  if (status.found && status.placeholderMarkers.length === 0) {
464
- return ok('changelog-target', `CHANGELOG has a final ${targetVersion} section`, ['CHANGELOG.md']);
523
+ return ok('changelog-target', `CHANGELOG has a final ${targetVersion} section`, [
524
+ 'CHANGELOG.md',
525
+ ]);
465
526
  }
466
527
  if (status.found) {
467
528
  return failed(
468
529
  'changelog-target',
469
530
  `CHANGELOG has a final ${targetVersion} section`,
470
531
  ['CHANGELOG.md'],
471
- [`Replace placeholder ${targetVersion} changelog scaffold before strict readiness: ${status.placeholderMarkers.join(', ')}`],
532
+ [
533
+ `Replace placeholder ${targetVersion} changelog scaffold before strict readiness: ${status.placeholderMarkers.join(', ')}`,
534
+ ],
472
535
  );
473
536
  }
474
537
  return pending(
@@ -483,15 +546,31 @@ function pythonDistCheck(targetVersion) {
483
546
  const wheel = `python/dist/audrey_memory-${targetVersion}-py3-none-any.whl`;
484
547
  const sdist = `python/dist/audrey_memory-${targetVersion}.tar.gz`;
485
548
  if (existsSync(fromRoot(wheel)) && existsSync(fromRoot(sdist))) {
486
- const verification = spawnSync('python', ['scripts/verify-python-package.py', '--version', targetVersion, '--json'], {
487
- cwd: ROOT,
488
- encoding: 'utf-8',
489
- });
549
+ const verification = spawnSync(
550
+ 'python',
551
+ ['scripts/verify-python-package.py', '--version', targetVersion, '--json'],
552
+ {
553
+ cwd: ROOT,
554
+ encoding: 'utf-8',
555
+ },
556
+ );
490
557
  if (verification.status !== 0) {
491
- const detail = verification.stderr.trim() || verification.stdout.trim() || `python verifier exited ${verification.status}`;
492
- return failed('python-dist', `Python ${targetVersion} artifacts verify`, [wheel, sdist], [detail]);
558
+ const detail =
559
+ verification.stderr.trim() ||
560
+ verification.stdout.trim() ||
561
+ `python verifier exited ${verification.status}`;
562
+ return failed(
563
+ 'python-dist',
564
+ `Python ${targetVersion} artifacts verify`,
565
+ [wheel, sdist],
566
+ [detail],
567
+ );
493
568
  }
494
- return ok('python-dist', `Python ${targetVersion} artifacts verify`, [wheel, sdist, 'python package verifier passed']);
569
+ return ok('python-dist', `Python ${targetVersion} artifacts verify`, [
570
+ wheel,
571
+ sdist,
572
+ 'python package verifier passed',
573
+ ]);
495
574
  }
496
575
  return pending(
497
576
  'python-dist',
@@ -501,10 +580,33 @@ function pythonDistCheck(targetVersion) {
501
580
  );
502
581
  }
503
582
 
504
- function pypiPublishCheck(targetVersion) {
505
- const pyproject = readText('python/pyproject.toml');
506
- const packageName = pyproject.match(/^name\s*=\s*"([^"]+)"/m)?.[1] ?? 'unknown';
507
- const version = pythonVersion();
583
+ async function pypiRegistryVersionStatus(packageName, targetVersion, fetchImpl = fetch) {
584
+ try {
585
+ const response = await fetchImpl(
586
+ `${PYPI_JSON_BASE}/${encodeURIComponent(packageName)}/${encodeURIComponent(targetVersion)}/json`,
587
+ {
588
+ headers: { accept: 'application/json' },
589
+ },
590
+ );
591
+ if (response.ok) return { ok: true, published: true, status: response.status };
592
+ if (response.status === 404) return { ok: true, published: false, status: response.status };
593
+ return {
594
+ ok: false,
595
+ published: false,
596
+ status: response.status,
597
+ error: `PyPI returned HTTP ${response.status}`,
598
+ };
599
+ } catch (error) {
600
+ return { ok: false, published: false, status: 'network-error', error: error.message };
601
+ }
602
+ }
603
+
604
+ export async function pypiPackageTargetStatus(
605
+ { packageName, version },
606
+ targetVersion,
607
+ options = {},
608
+ ) {
609
+ const env = options.env ?? process.env;
508
610
  const evidence = [`python package=${packageName}`, `python version=${version ?? 'missing'}`];
509
611
 
510
612
  if (version !== targetVersion) {
@@ -516,17 +618,51 @@ function pypiPublishCheck(targetVersion) {
516
618
  );
517
619
  }
518
620
 
519
- const credentialEnv = PYPI_CREDENTIAL_ENVS.find(name => Boolean(process.env[name]));
621
+ if (options.checkRegistry === true) {
622
+ const registry = await pypiRegistryVersionStatus(packageName, targetVersion, options.fetchImpl);
623
+ if (registry.ok && registry.published) {
624
+ return ok('pypi-package-target', `PyPI package is already published as ${targetVersion}`, [
625
+ ...evidence,
626
+ `registry=${packageName}==${targetVersion}`,
627
+ ]);
628
+ }
629
+ if (!registry.ok) {
630
+ return pending(
631
+ 'pypi-package-target',
632
+ `PyPI package is ready to publish as ${targetVersion}`,
633
+ evidence,
634
+ [
635
+ `Verify PyPI registry availability before publishing (${registry.error ?? `status=${registry.status}`})`,
636
+ ],
637
+ );
638
+ }
639
+
640
+ evidence.push(`registry=${packageName}==${targetVersion}:unpublished`);
641
+ }
642
+ const credentialEnv = PYPI_CREDENTIAL_ENVS.find(name => Boolean(env[name]));
520
643
  if (!credentialEnv) {
521
644
  return pending(
522
645
  'pypi-package-target',
523
646
  `PyPI package is ready to publish as ${targetVersion}`,
524
647
  evidence,
525
- [`Provide runtime PyPI publish credentials (${PYPI_CREDENTIAL_ENVS.join(', ')}) or trusted-publisher evidence before publishing`],
648
+ [
649
+ `Provide runtime PyPI publish credentials (${PYPI_CREDENTIAL_ENVS.join(', ')}) or trusted-publisher evidence before publishing`,
650
+ ],
526
651
  );
527
652
  }
528
653
 
529
- return ok('pypi-package-target', `PyPI package is ready to publish as ${targetVersion}`, [...evidence, `credentialEnv=${credentialEnv}`]);
654
+ return ok('pypi-package-target', `PyPI package is ready to publish as ${targetVersion}`, [
655
+ ...evidence,
656
+ `credentialEnv=${credentialEnv}`,
657
+ ]);
658
+ }
659
+
660
+ async function pypiPublishCheck(targetVersion, options = {}) {
661
+ const pyproject = readText('python/pyproject.toml');
662
+ const packageName = pyproject.match(/^name\s*=\s*"([^"]+)"/m)?.[1] ?? 'unknown';
663
+ return pypiPackageTargetStatus({ packageName, version: pythonVersion() }, targetVersion, {
664
+ checkRegistry: options.checkPypiRegistry === true,
665
+ });
530
666
  }
531
667
 
532
668
  async function paperChecks() {
@@ -547,14 +683,19 @@ async function paperChecks() {
547
683
  ];
548
684
 
549
685
  if (failures.length > 0) {
550
- return failed('paper-artifacts', 'Paper artifacts verify locally', [
551
- 'paper:claims',
552
- 'paper:publication-pack',
553
- 'paper:arxiv:verify',
554
- 'paper:launch-plan',
555
- 'paper:launch-results',
556
- 'paper:bundle:verify',
557
- ], failures);
686
+ return failed(
687
+ 'paper-artifacts',
688
+ 'Paper artifacts verify locally',
689
+ [
690
+ 'paper:claims',
691
+ 'paper:publication-pack',
692
+ 'paper:arxiv:verify',
693
+ 'paper:launch-plan',
694
+ 'paper:launch-results',
695
+ 'paper:bundle:verify',
696
+ ],
697
+ failures,
698
+ );
558
699
  }
559
700
  return ok('paper-artifacts', 'Paper artifacts verify locally', [
560
701
  `${claimReport.claims.length} claim(s)`,
@@ -569,17 +710,28 @@ async function paperChecks() {
569
710
  async function browserPublicationCheck() {
570
711
  const report = await verifyBrowserLaunchResults();
571
712
  if (!report.ok) {
572
- return failed('browser-publication', 'Browser publication results are valid', [report.results], report.failures);
713
+ return failed(
714
+ 'browser-publication',
715
+ 'Browser publication results are valid',
716
+ [report.results],
717
+ report.failures,
718
+ );
573
719
  }
574
720
  if (!report.ready) {
575
721
  return pending(
576
722
  'browser-publication',
577
723
  'Paper/browser launch targets are submitted',
578
- [`${report.targets.filter(target => target.status === 'submitted').length}/${report.targets.length} submitted`],
724
+ [
725
+ `${report.targets.filter(target => target.status === 'submitted').length}/${report.targets.length} submitted`,
726
+ ],
579
727
  report.blockers,
580
728
  );
581
729
  }
582
- return ok('browser-publication', 'Paper/browser launch targets are submitted', report.targets.map(target => `${target.id}: ${target.publicUrl}`));
730
+ return ok(
731
+ 'browser-publication',
732
+ 'Paper/browser launch targets are submitted',
733
+ report.targets.map(target => `${target.id}: ${target.publicUrl}`),
734
+ );
583
735
  }
584
736
 
585
737
  function arxivCompileCheck() {
@@ -601,7 +753,12 @@ function arxivCompileCheck() {
601
753
  async function externalEvidenceCheck() {
602
754
  const report = await verifyExternalGuardBenchEvidence({ allowPending: true, write: false });
603
755
  if (!report.ok) {
604
- return failed('external-evidence', 'External GuardBench evidence verifies', [report.outRoot], report.failures);
756
+ return failed(
757
+ 'external-evidence',
758
+ 'External GuardBench evidence verifies',
759
+ [report.outRoot],
760
+ report.failures,
761
+ );
605
762
  }
606
763
  const pendingRows = report.adapters.filter(adapter => adapter.status !== 'verified');
607
764
  if (pendingRows.length > 0) {
@@ -609,10 +766,17 @@ async function externalEvidenceCheck() {
609
766
  'external-evidence',
610
767
  'External Mem0/Zep GuardBench evidence is live-verified',
611
768
  report.adapters.map(adapter => `${adapter.id}: ${adapter.status}/${adapter.evidenceKind}`),
612
- pendingRows.map(adapter => `${adapter.id}: ${adapter.missingEnv?.length ? `missing ${adapter.missingEnv.join(', ')}` : adapter.evidenceKind}`),
769
+ pendingRows.map(
770
+ adapter =>
771
+ `${adapter.id}: ${adapter.missingEnv?.length ? `missing ${adapter.missingEnv.join(', ')}` : adapter.evidenceKind}`,
772
+ ),
613
773
  );
614
774
  }
615
- return ok('external-evidence', 'External Mem0/Zep GuardBench evidence is live-verified', report.adapters.map(adapter => `${adapter.id}: verified`));
775
+ return ok(
776
+ 'external-evidence',
777
+ 'External Mem0/Zep GuardBench evidence is live-verified',
778
+ report.adapters.map(adapter => `${adapter.id}: verified`),
779
+ );
616
780
  }
617
781
 
618
782
  function npmVersionMissing(result) {
@@ -626,7 +790,9 @@ export function npmPackageTargetStatus(pkg, targetVersion, run = runNpm) {
626
790
  'npm-package-target',
627
791
  `npm package is ready to publish as ${targetVersion}`,
628
792
  [`package.json version=${pkg.version}`],
629
- [`Cut the npm package only after version is bumped to ${targetVersion} and npm OTP/auth is available`],
793
+ [
794
+ `Cut the npm package only after version is bumped to ${targetVersion} and npm OTP/auth is available`,
795
+ ],
630
796
  );
631
797
  }
632
798
 
@@ -641,9 +807,14 @@ export function npmPackageTargetStatus(pkg, targetVersion, run = runNpm) {
641
807
  `registry=${packageSpec}`,
642
808
  ]);
643
809
  }
644
- return failed('npm-package-target', `npm package registry state is coherent for ${targetVersion}`, evidence, [
645
- `npm registry returned unexpected version for ${packageSpec}: ${registryVersion || 'empty'}`,
646
- ]);
810
+ return failed(
811
+ 'npm-package-target',
812
+ `npm package registry state is coherent for ${targetVersion}`,
813
+ evidence,
814
+ [
815
+ `npm registry returned unexpected version for ${packageSpec}: ${registryVersion || 'empty'}`,
816
+ ],
817
+ );
647
818
  }
648
819
 
649
820
  if (!npmVersionMissing(registryStatus)) {
@@ -662,7 +833,9 @@ export function npmPackageTargetStatus(pkg, targetVersion, run = runNpm) {
662
833
  'npm-package-target',
663
834
  `npm package is ready to publish as ${targetVersion}`,
664
835
  evidence,
665
- [`Authenticate npm CLI for ${NPM_REGISTRY} before publishing (${commandSummary(authStatus)})`],
836
+ [
837
+ `Authenticate npm CLI for ${NPM_REGISTRY} before publishing (${commandSummary(authStatus)})`,
838
+ ],
666
839
  );
667
840
  }
668
841
 
@@ -688,12 +861,13 @@ export async function verifyReleaseReadiness(options = {}) {
688
861
  await browserPublicationCheck(),
689
862
  await externalEvidenceCheck(),
690
863
  packageDryRunCheck(targetVersion),
691
- pypiPublishCheck(targetVersion),
864
+ await pypiPublishCheck(targetVersion, options),
692
865
  ];
693
866
  const failures = checks.flatMap(row => row.failures.map(failure => `${row.id}: ${failure}`));
694
867
  const blockers = checks.flatMap(row => row.blockers.map(blocker => `${row.id}: ${blocker}`));
695
868
  const ready = failures.length === 0 && blockers.length === 0;
696
- const okStatus = failures.length === 0 && (options.allowPending === true || blockers.length === 0);
869
+ const okStatus =
870
+ failures.length === 0 && (options.allowPending === true || blockers.length === 0);
697
871
 
698
872
  return {
699
873
  schemaVersion: '1.0.0',
@@ -722,7 +896,9 @@ async function main() {
722
896
  } else if (report.ready) {
723
897
  console.log(`Audrey ${report.targetVersion} release readiness passed.`);
724
898
  } else if (report.ok) {
725
- console.log(`Audrey ${report.targetVersion} release readiness has ${report.blockers.length} pending blocker(s).`);
899
+ console.log(
900
+ `Audrey ${report.targetVersion} release readiness has ${report.blockers.length} pending blocker(s).`,
901
+ );
726
902
  for (const blocker of report.blockers) console.log(`- ${blocker}`);
727
903
  } else {
728
904
  console.error(`Audrey ${report.targetVersion} release readiness failed.`);
@@ -733,7 +909,10 @@ async function main() {
733
909
  if (!report.ok) process.exit(1);
734
910
  }
735
911
 
736
- if (process.argv[1] && resolve(process.argv[1]).toLowerCase() === fileURLToPath(import.meta.url).toLowerCase()) {
912
+ if (
913
+ process.argv[1] &&
914
+ resolve(process.argv[1]).toLowerCase() === fileURLToPath(import.meta.url).toLowerCase()
915
+ ) {
737
916
  main().catch(error => {
738
917
  console.error(error.stack ?? error.message);
739
918
  process.exit(1);