@pome-sh/cli 0.23.0 → 0.23.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.
package/README.md CHANGED
@@ -79,8 +79,19 @@ Three rules CI must honor:
79
79
  whose criteria could not all be graded exits `1` rather than mapping its
80
80
  partial score to a code — a run whose checks never ran is not a green CI
81
81
  signal. The cost is stated rather than hidden: **`1` cannot tell "the agent
82
- regressed" from "we could not grade it."** Read the verdict word printed
83
- beside the score (`INCOMPLETE` vs a sub-threshold number) to separate them.
82
+ regressed" from "we could not grade it."** To separate them programmatically,
83
+ do not compare `score` against `pass_threshold` yourself a run with a third
84
+ of its criteria unevaluated can still read `score: 100, pass_threshold: 100`
85
+ with nothing in those two fields alone saying so. Read `state` in the
86
+ `verdict.json` a hosted `pome run` writes to
87
+ `<artifacts-dir>/<task-slug>/<session-id>/verdict.json`: `"pass"`, `"fail"`,
88
+ or `"incomplete"` — the same word the terminal prints beside the score, and
89
+ the field to gate on. The `evaluated` / `not_evaluated` / `pre_satisfied` /
90
+ `total` counts alongside it say how much of the task `score` covers:
91
+ **`score` is a percentage over `evaluated` alone**, so `not_evaluated > 0`
92
+ means `score` is silent about part of the run, and `evaluated: 0` means it
93
+ scored nothing at all (the cloud sends `0` there for want of a denominator
94
+ — "nothing was scored", not "nothing was correct").
84
95
  - **Trial groups map as a whole.** `pome run -n k` (k>1) collapses the whole
85
96
  group to one code: `0` = at least one trial completed and every completed
86
97
  trial passed; `1` = at least one completed trial failed its threshold **or was
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "pome-sh",
3
- "version": "0.23.0",
4
- "git_sha": "ace5f001527e5a1d68cbe3ba5b534338e333a051",
5
- "build_time": "2026-08-10T10:29:32.549Z"
3
+ "version": "0.23.2",
4
+ "git_sha": "9fe20d1ba7f0f9b40cfb7561e4ceab144c22c71d",
5
+ "build_time": "2026-08-10T13:45:05.230Z"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  import { getAvailablePort } from './chunk-XDU6TD4O.js';
2
2
  import { buildEgressAllowlist, readBlockedEgress } from './chunk-CBFKZZBR.js';
3
- import { parseTaskFile, seedStateForTwin, runAgentCommand, writeRunArtifactsCore } from './chunk-KS4DD6JC.js';
3
+ import { parseTaskFile, seedStateForTwin, runAgentCommand, writeRunArtifactsCore } from './chunk-N4UTEHX5.js';
4
4
  import { createRecorder, bootTwin } from './chunk-TG22SRUL.js';
5
5
  import { eventSchema } from './chunk-VBATFCWR.js';
6
6
  import { redactSecrets, redactEvent } from './chunk-SG6ZTIMT.js';
@@ -1232,6 +1232,10 @@ function outcomeOf(result) {
1232
1232
  if (result.skipped) return "skipped";
1233
1233
  return result.passed ? "passed" : "failed";
1234
1234
  }
1235
+ var PRE_SATISFIED_REASON = "already_true_in_seed";
1236
+ function isPreSatisfied(result) {
1237
+ return result.skipped && result.reason === PRE_SATISFIED_REASON;
1238
+ }
1235
1239
  function scoreStatus(score, passThreshold) {
1236
1240
  if (!score.evaluated || !score.can_pass) return "incomplete";
1237
1241
  return score.satisfaction >= passThreshold ? "pass" : "fail";
@@ -1258,15 +1262,31 @@ function twinSkipSuffix(result) {
1258
1262
  const twinRelated = outcome === "skipped" || outcome === "errored" || /no_matching_predicate|no matching predicate/i.test(result.reason);
1259
1263
  return twinRelated ? ` (twin: ${twin})` : "";
1260
1264
  }
1265
+ function criteriaWord(n) {
1266
+ return n === 1 ? "criterion" : "criteria";
1267
+ }
1268
+ function evaluationCounts(score) {
1269
+ const evaluated = score.total_required;
1270
+ const notEvaluated = score.skipped + score.errored - score.preSatisfied;
1271
+ return {
1272
+ evaluated,
1273
+ notEvaluated,
1274
+ preSatisfied: score.preSatisfied,
1275
+ total: evaluated + notEvaluated + score.preSatisfied
1276
+ };
1277
+ }
1261
1278
  function scoreCountsSummary(score) {
1262
1279
  return `${score.passed ?? 0} passed, ${score.failed ?? 0} failed, ${score.skipped ?? 0} skipped, ${score.errored ?? 0} errored`;
1263
1280
  }
1264
1281
  function runScoreLine(score, passThreshold, unevaluatedNumericLabel) {
1265
1282
  const status = scoreStatus(score, passThreshold);
1266
1283
  if (status === "incomplete") {
1267
- const notEvaluated = score.skipped + score.errored;
1268
- const total = score.total_required + notEvaluated;
1269
- return `score: incomplete \u2014 ${notEvaluated} of ${total} criteria not evaluated; ${scoreCountsSummary(score)}; ${unevaluatedNumericLabel}: ${score.satisfaction}/100`;
1284
+ const { notEvaluated: unreached, total } = evaluationCounts(score);
1285
+ if (score.total_required === 0 && unreached === 0 && score.preSatisfied > 0) {
1286
+ return `score: incomplete \u2014 nothing was at risk (${score.preSatisfied} ${criteriaWord(score.preSatisfied)} already true in the seed); ${scoreCountsSummary(score)}; ${unevaluatedNumericLabel}: ${score.satisfaction}/100`;
1287
+ }
1288
+ const preSatisfiedClause = score.preSatisfied > 0 ? ` (${score.preSatisfied} already true in the seed)` : "";
1289
+ return `score: incomplete \u2014 ${unreached} of ${total} criteria not evaluated${preSatisfiedClause}; ${scoreCountsSummary(score)}; ${unevaluatedNumericLabel}: ${score.satisfaction}/100`;
1270
1290
  }
1271
1291
  return `score: ${score.satisfaction}/100`;
1272
1292
  }
@@ -1434,16 +1454,21 @@ function scoreFromFinalizeResponse(finalized) {
1434
1454
  const failed = results.filter((r) => outcomeOf(r) === "failed").length;
1435
1455
  const errored = results.filter((r) => outcomeOf(r) === "errored").length;
1436
1456
  const skipped = results.filter((r) => outcomeOf(r) === "skipped").length;
1457
+ const preSatisfied = results.filter(
1458
+ (r) => outcomeOf(r) === "skipped" && isPreSatisfied(r)
1459
+ ).length;
1437
1460
  const totalRequired = passed + failed;
1461
+ const unresolvedAbstentions = skipped - preSatisfied + errored;
1438
1462
  return {
1439
1463
  satisfaction: finalized.score,
1440
1464
  passed,
1441
1465
  failed,
1442
1466
  skipped,
1443
1467
  errored,
1468
+ preSatisfied,
1444
1469
  total_required: totalRequired,
1445
1470
  evaluated: hasCriteriaResults ? totalRequired > 0 : true,
1446
- can_pass: hasCriteriaResults ? totalRequired > 0 && skipped === 0 && errored === 0 : true,
1471
+ can_pass: hasCriteriaResults ? totalRequired > 0 && unresolvedAbstentions === 0 : true,
1447
1472
  results,
1448
1473
  judge_model: finalized.judge_model ?? null,
1449
1474
  judge_tokens_in: null,
@@ -1613,4 +1638,4 @@ function splitCommand(command) {
1613
1638
  return file ? { file, args } : null;
1614
1639
  }
1615
1640
 
1616
- export { createHostedClient, criterionMarkerLabel, markerFor, outcomeOf, parseGitHubSeedState, parseTaskFile, perTwinReturnedByCloud, readCodeCriteria, readConfigTwins, readLatestRun, readMetaSummary, redactJsonl, runAgentCommand, runScoreLine, scoreCountsSummary, scoreFromFinalizeResponse, scoreStatus, seedStateForTwin, toTwinHttpEvent, twinSkipSuffix, uploadRunBlobs, writeRunArtifactsCore };
1641
+ export { createHostedClient, criterionMarkerLabel, evaluationCounts, isPreSatisfied, markerFor, outcomeOf, parseGitHubSeedState, parseTaskFile, perTwinReturnedByCloud, readCodeCriteria, readConfigTwins, readLatestRun, readMetaSummary, redactJsonl, runAgentCommand, runScoreLine, scoreCountsSummary, scoreFromFinalizeResponse, scoreStatus, seedStateForTwin, toTwinHttpEvent, twinSkipSuffix, uploadRunBlobs, writeRunArtifactsCore };
@@ -1,5 +1,5 @@
1
1
  import { readManifest, normalizeManifestTwins } from './chunk-KUVTL4NZ.js';
2
- import { createHostedClient, perTwinReturnedByCloud, parseTaskFile, runAgentCommand, writeRunArtifactsCore, toTwinHttpEvent, redactJsonl, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus } from './chunk-KS4DD6JC.js';
2
+ import { createHostedClient, perTwinReturnedByCloud, parseTaskFile, runAgentCommand, writeRunArtifactsCore, toTwinHttpEvent, redactJsonl, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, evaluationCounts } from './chunk-N4UTEHX5.js';
3
3
  import { MOUNTED_TWINS, HostedAuthError, HostedDiscardRefusedError, HostedQuotaError, HostedOrchError, HostedTrialError, agentResponseSchema } from './chunk-PQYIAA6K.js';
4
4
  import { redactSecrets, redactEvent } from './chunk-SG6ZTIMT.js';
5
5
  import { existsSync } from 'node:fs';
@@ -11,8 +11,13 @@ import { promisify } from 'node:util';
11
11
  import { createInterface } from 'node:readline';
12
12
  import { randomUUID, createHash } from 'node:crypto';
13
13
 
14
- var VERDICT_ARTIFACT_VERSION = 1;
14
+ var VERDICT_ARTIFACT_VERSION = 2;
15
15
  var VERDICT_FILENAME = "verdict.json";
16
+ var VALID_STATES = /* @__PURE__ */ new Set([
17
+ "pass",
18
+ "fail",
19
+ "incomplete"
20
+ ]);
16
21
  async function writeVerdictArtifact(runDir, verdict) {
17
22
  await writeFile(
18
23
  join(runDir, VERDICT_FILENAME),
@@ -21,7 +26,7 @@ async function writeVerdictArtifact(runDir, verdict) {
21
26
  "utf8"
22
27
  );
23
28
  }
24
- function isVerdictArtifact(parsed) {
29
+ function looksLikeVerdictArtifactBase(parsed) {
25
30
  if (typeof parsed !== "object" || parsed === null) return false;
26
31
  const v = parsed;
27
32
  if (v.source !== "cloud-finalize") return false;
@@ -40,33 +45,46 @@ function isVerdictArtifact(parsed) {
40
45
  return typeof criterion === "object" && criterion !== null && typeof criterion.text === "string" && typeof result.reason === "string" && typeof result.passed === "boolean" && typeof result.skipped === "boolean";
41
46
  });
42
47
  }
43
- function normalizeVerdictArtifact(parsed) {
44
- const { scenario_path: legacyPath, task_path: taskPath, ...rest } = parsed;
45
- return { ...rest, task_path: taskPath ?? legacyPath };
48
+ function isVerdictArtifact(parsed) {
49
+ if (!looksLikeVerdictArtifactBase(parsed)) return false;
50
+ const v = parsed;
51
+ if (v.version !== VERDICT_ARTIFACT_VERSION) return false;
52
+ if (typeof v.task_path !== "string") return false;
53
+ if (typeof v.state !== "string" || !VALID_STATES.has(v.state)) return false;
54
+ if (typeof v.evaluated !== "number") return false;
55
+ if (typeof v.not_evaluated !== "number") return false;
56
+ if (typeof v.pre_satisfied !== "number") return false;
57
+ if (typeof v.total !== "number") return false;
58
+ return true;
46
59
  }
47
- async function readVerdictArtifact(runDir) {
60
+ async function readVerdictArtifactDetailed(runDir) {
48
61
  const path = join(runDir, VERDICT_FILENAME);
49
62
  let raw;
50
63
  try {
51
64
  raw = await readFile(path, "utf8");
52
65
  } catch {
53
- return null;
66
+ return { status: "unreadable" };
54
67
  }
68
+ let parsed;
55
69
  try {
56
- const parsed = JSON.parse(raw);
57
- if (!isVerdictArtifact(parsed)) return null;
58
- return { runDir, verdict: normalizeVerdictArtifact(parsed) };
70
+ parsed = JSON.parse(raw);
59
71
  } catch {
60
- return null;
72
+ return { status: "unreadable" };
61
73
  }
74
+ if (!looksLikeVerdictArtifactBase(parsed)) return { status: "unreadable" };
75
+ const version = typeof parsed.version === "number" ? parsed.version : null;
76
+ if (version !== VERDICT_ARTIFACT_VERSION) return { status: "stale-version", version };
77
+ if (!isVerdictArtifact(parsed)) return { status: "unreadable" };
78
+ return { status: "ok", trial: { runDir, verdict: parsed } };
62
79
  }
63
- async function scanVerdictArtifacts(artifactsRoot) {
64
- const found = [];
80
+ async function scanVerdictArtifactsDetailed(artifactsRoot) {
81
+ const trials = [];
82
+ const staleVersionDirs = [];
65
83
  let slugs;
66
84
  try {
67
85
  slugs = await readdir(artifactsRoot);
68
86
  } catch {
69
- return found;
87
+ return { trials, staleVersionDirs };
70
88
  }
71
89
  for (const slug of slugs) {
72
90
  const slugDir = join(artifactsRoot, slug);
@@ -77,11 +95,13 @@ async function scanVerdictArtifacts(artifactsRoot) {
77
95
  continue;
78
96
  }
79
97
  for (const runId of runIds) {
80
- const trial = await readVerdictArtifact(join(slugDir, runId));
81
- if (trial) found.push(trial);
98
+ const runDir = join(slugDir, runId);
99
+ const result = await readVerdictArtifactDetailed(runDir);
100
+ if (result.status === "ok") trials.push(result.trial);
101
+ else if (result.status === "stale-version") staleVersionDirs.push(runDir);
82
102
  }
83
103
  }
84
- return found;
104
+ return { trials, staleVersionDirs };
85
105
  }
86
106
  function groupRunSets(trials) {
87
107
  const byKey = /* @__PURE__ */ new Map();
@@ -116,21 +136,35 @@ function latestFailedRunSet(sets) {
116
136
  return null;
117
137
  }
118
138
  async function discoverRunSet(target) {
119
- const anchor = await readVerdictArtifact(target);
120
- if (anchor) {
139
+ const anchorResult = await readVerdictArtifactDetailed(target);
140
+ if (anchorResult.status === "stale-version") {
141
+ return { kind: "trial-dir", set: null, totalSets: 0, staleVersionCount: 1 };
142
+ }
143
+ if (anchorResult.status === "ok") {
144
+ const anchor = anchorResult.trial;
121
145
  const root = join(target, "..", "..");
122
- const sets2 = groupRunSets(await scanVerdictArtifacts(root));
146
+ const { trials: trials2, staleVersionDirs: staleVersionDirs2 } = await scanVerdictArtifactsDetailed(root);
147
+ const sets2 = groupRunSets(trials2);
123
148
  const own = sets2.find(
124
149
  (s) => anchor.verdict.group_id !== null && s.groupId === anchor.verdict.group_id || anchor.verdict.group_id === null && s.trials.length === 1 && s.trials[0].verdict.session_id === anchor.verdict.session_id
125
150
  ) ?? groupRunSets([anchor])[0];
126
- return { kind: "trial-dir", set: own, totalSets: Math.max(sets2.length, 1) };
151
+ return {
152
+ kind: "trial-dir",
153
+ set: own,
154
+ totalSets: Math.max(sets2.length, 1),
155
+ staleVersionCount: staleVersionDirs2.length
156
+ };
157
+ }
158
+ if (!existsSync(target)) {
159
+ return { kind: "root", set: null, totalSets: 0, staleVersionCount: 0 };
127
160
  }
128
- if (!existsSync(target)) return { kind: "root", set: null, totalSets: 0 };
129
- const sets = groupRunSets(await scanVerdictArtifacts(target));
161
+ const { trials, staleVersionDirs } = await scanVerdictArtifactsDetailed(target);
162
+ const sets = groupRunSets(trials);
130
163
  return {
131
164
  kind: "root",
132
165
  set: latestFailedRunSet(sets),
133
- totalSets: sets.length
166
+ totalSets: sets.length,
167
+ staleVersionCount: staleVersionDirs.length
134
168
  };
135
169
  }
136
170
  async function loadTrialEvents(runDir) {
@@ -1067,6 +1101,7 @@ async function runTaskHosted(options) {
1067
1101
  const verdict = scoreStatus(score, scenario.config.passThreshold);
1068
1102
  const exitCode = verdict === "pass" ? 0 : 1;
1069
1103
  try {
1104
+ const counts = evaluationCounts(score);
1070
1105
  await writeVerdictArtifact(artifacts.runDir, {
1071
1106
  version: VERDICT_ARTIFACT_VERSION,
1072
1107
  source: "cloud-finalize",
@@ -1079,7 +1114,12 @@ async function runTaskHosted(options) {
1079
1114
  judge_model: score.judge_model,
1080
1115
  score: finalized.score,
1081
1116
  pass_threshold: scenario.config.passThreshold,
1117
+ state: verdict,
1082
1118
  passed: exitCode === 0,
1119
+ evaluated: counts.evaluated,
1120
+ not_evaluated: counts.notEvaluated,
1121
+ pre_satisfied: counts.preSatisfied,
1122
+ total: counts.total,
1083
1123
  criteria_results: score.results,
1084
1124
  duration_ms: durationMs,
1085
1125
  finalized_at: (/* @__PURE__ */ new Date()).toISOString()
@@ -1176,4 +1216,4 @@ async function abandonBestEffort(client, sessionId, errorCode) {
1176
1216
  }
1177
1217
  }
1178
1218
 
1179
- export { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, DEFAULT_DOCS_SITE_ORIGIN, clearLocalCredentials, discoverRunSet, ensurePomeGitignored, friendlyHostedError, loadTrialEvents, persistCredentialsAfterLogin, postAgentResolver, readLinkCache, resolveCachedAgentId, resolveCredentials, resolveRunAgentIdentity, resolveSeams, runSessionCreate, runSessionList, runSessionStop, runTaskHosted, writeLinkCache };
1219
+ export { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, DEFAULT_DOCS_SITE_ORIGIN, VERDICT_ARTIFACT_VERSION, clearLocalCredentials, discoverRunSet, ensurePomeGitignored, friendlyHostedError, loadTrialEvents, persistCredentialsAfterLogin, postAgentResolver, readLinkCache, resolveCachedAgentId, resolveCredentials, resolveRunAgentIdentity, resolveSeams, runSessionCreate, runSessionList, runSessionStop, runTaskHosted, writeLinkCache };
@@ -1,9 +1,9 @@
1
1
  import { newGroupId, reassuranceBox, twinReadyLine, trialsHeaderLine, trialLine, summaryLines, evaluatingLine, criterionPhrase } from './chunk-RGZBC7NF.js';
2
2
  import { DemoCapacityError, capacityLabel, parseCapacityMarker, capacityKindFrom } from './chunk-ZX4WNSZ5.js';
3
- import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-S3RNVG6R.js';
3
+ import { runTask, demoTaskPath, DEMO_TASK_NAME, DEMO_REPO } from './chunk-IQ6LOK4D.js';
4
4
  import { getAvailablePort } from './chunk-XDU6TD4O.js';
5
5
  import './chunk-CBFKZZBR.js';
6
- import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, outcomeOf } from './chunk-KS4DD6JC.js';
6
+ import { createHostedClient, parseTaskFile, uploadRunBlobs, scoreFromFinalizeResponse, scoreStatus, outcomeOf } from './chunk-N4UTEHX5.js';
7
7
  import './chunk-NW7HGA2K.js';
8
8
  import { HostedQuotaError, HostedOrchError } from './chunk-PQYIAA6K.js';
9
9
  import './chunk-SGDUD7KK.js';
@@ -1,7 +1,7 @@
1
1
  import { newGroupId, criterionPhrase } from './chunk-RGZBC7NF.js';
2
- import { runTaskHosted, resolveRunAgentIdentity } from './chunk-OX2CRKHX.js';
2
+ import { runTaskHosted, resolveRunAgentIdentity } from './chunk-NRECWO3Y.js';
3
3
  import './chunk-KUVTL4NZ.js';
4
- import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-KS4DD6JC.js';
4
+ import { createHostedClient, parseTaskFile, outcomeOf } from './chunk-N4UTEHX5.js';
5
5
  import './chunk-NW7HGA2K.js';
6
6
  import { HostedQuotaError, HostedTrialError } from './chunk-PQYIAA6K.js';
7
7
  import './chunk-SGDUD7KK.js';
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, loadTrialEvents, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-OX2CRKHX.js';
2
+ import { DEFAULT_CONTROL_PLANE_URL, DEFAULT_DASHBOARD_URL, clearLocalCredentials, friendlyHostedError, runSessionCreate, runSessionList, runSessionStop, resolveCredentials, runTaskHosted, discoverRunSet, VERDICT_ARTIFACT_VERSION, loadTrialEvents, persistCredentialsAfterLogin, DEFAULT_DOCS_SITE_ORIGIN, resolveSeams, resolveCachedAgentId, readLinkCache, postAgentResolver, writeLinkCache, ensurePomeGitignored } from '../../chunk-NRECWO3Y.js';
3
3
  import { readManifest, writeManifest, MANIFEST_JSON, readRequiredManifest, normalizeManifestTwins } from '../../chunk-KUVTL4NZ.js';
4
- import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-S3RNVG6R.js';
4
+ import { assetPath, runTask, resolvePackageRoot, DEMO_TASK_NAME, demoTaskPath } from '../../chunk-IQ6LOK4D.js';
5
5
  import '../../chunk-XDU6TD4O.js';
6
6
  import '../../chunk-CBFKZZBR.js';
7
- import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, readConfigTwins, scoreCountsSummary, markerFor, outcomeOf, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs } from '../../chunk-KS4DD6JC.js';
7
+ import { parseTaskFile, scoreStatus, runScoreLine, readLatestRun, readMetaSummary, readConfigTwins, scoreCountsSummary, markerFor, outcomeOf, criterionMarkerLabel, twinSkipSuffix, readCodeCriteria, createHostedClient, toTwinHttpEvent, redactJsonl, scoreFromFinalizeResponse, parseGitHubSeedState, uploadRunBlobs, isPreSatisfied } from '../../chunk-N4UTEHX5.js';
8
8
  import '../../chunk-NW7HGA2K.js';
9
9
  import { MOUNTED_TWINS, deriveAgentSlug, exitCodeFor, HostedUsageError, HostedOrchError, HostedAuthError, HostedQuotaError } from '../../chunk-PQYIAA6K.js';
10
10
  import { TAPE_ASSERTABLE_TOOLS } from '../../chunk-FKZZWWYC.js';
@@ -4360,7 +4360,7 @@ function renderGroupedSignatures(trials) {
4360
4360
  for (const trial of trials) {
4361
4361
  for (const result of trial.verdict.criteria_results) {
4362
4362
  const key = result.criterion.text;
4363
- const outcome = outcomeOf(result);
4363
+ const outcome = isPreSatisfied(result) ? "excluded" : outcomeOf(result);
4364
4364
  if (outcome === "failed") {
4365
4365
  const entry = byCriterion.get(key) ?? {
4366
4366
  marker: criterionMarker(result.criterion),
@@ -4375,10 +4375,12 @@ function renderGroupedSignatures(trials) {
4375
4375
  }
4376
4376
  }
4377
4377
  const passedEverywhere = [];
4378
+ const preSatisfiedEverywhere = [];
4378
4379
  const notUniformlyEvaluated = [];
4379
4380
  for (const [key, seen] of outcomesSeen) {
4380
4381
  if (byCriterion.has(key)) continue;
4381
4382
  if (seen.size === 1 && seen.has("passed")) passedEverywhere.push(key);
4383
+ else if (seen.size === 1 && seen.has("excluded")) preSatisfiedEverywhere.push(key);
4382
4384
  else notUniformlyEvaluated.push(key);
4383
4385
  }
4384
4386
  const completed = trials.length;
@@ -4389,7 +4391,7 @@ function renderGroupedSignatures(trials) {
4389
4391
  return `${idx + 1}. ${marker} ${flattenLine(text)} \u2014 failed in ${hits.length} of ${completed} completed trials
4390
4392
  ${lines.join("\n")}`;
4391
4393
  });
4392
- if (blocks.length === 0 && passedEverywhere.length === 0 && notUniformlyEvaluated.length === 0) {
4394
+ if (blocks.length === 0 && passedEverywhere.length === 0 && preSatisfiedEverywhere.length === 0 && notUniformlyEvaluated.length === 0) {
4393
4395
  return "(no criteria recorded)";
4394
4396
  }
4395
4397
  const notes = [];
@@ -4401,9 +4403,14 @@ ${lines.join("\n")}`;
4401
4403
  `passed in every completed trial: ${passedEverywhere.map((t) => `"${flattenLine(t)}"`).join(" \xB7 ")}`
4402
4404
  );
4403
4405
  }
4406
+ if (preSatisfiedEverywhere.length > 0) {
4407
+ notes.push(
4408
+ `already true in the seed in every completed trial \u2014 excluded from the score, nothing here to fix: ${preSatisfiedEverywhere.map((t) => `"${flattenLine(t)}"`).join(" \xB7 ")}`
4409
+ );
4410
+ }
4404
4411
  if (notUniformlyEvaluated.length > 0) {
4405
4412
  notes.push(
4406
- `not uniformly evaluated (skipped or errored in some trials \u2014 no pass is claimed for these): ${notUniformlyEvaluated.map((t) => `"${flattenLine(t)}"`).join(" \xB7 ")}`
4413
+ `not uniformly evaluated (not evaluated in some trials \u2014 no pass is claimed for these): ${notUniformlyEvaluated.map((t) => `"${flattenLine(t)}"`).join(" \xB7 ")}`
4407
4414
  );
4408
4415
  }
4409
4416
  return [...blocks, ...notes].join("\n");
@@ -4490,7 +4497,7 @@ var DEFAULT_AGENT_FILE = "examples/agents/scripted-triage-agent.ts";
4490
4497
  var DEFAULT_AGENT_COMMAND = `node ${DEFAULT_AGENT_FILE}`;
4491
4498
  var MANIFEST_SCHEMA_URL = "https://pome.sh/schemas/v1/pome.json";
4492
4499
  function readPackageVersion() {
4493
- if ("0.23.0".length > 0) return "0.23.0";
4500
+ if ("0.23.2".length > 0) return "0.23.2";
4494
4501
  try {
4495
4502
  const here = dirname(fileURLToPath(import.meta.url));
4496
4503
  const candidates = [
@@ -4983,7 +4990,7 @@ function createProgram() {
4983
4990
  taskForRuns.config.runs
4984
4991
  );
4985
4992
  if (k > 1) {
4986
- const { runTrialGroup } = await import('../../runTrialGroup-PGDK4KZ2.js');
4993
+ const { runTrialGroup } = await import('../../runTrialGroup-M4CP7WKY.js');
4987
4994
  const fileForRerun = relative(process.cwd(), file);
4988
4995
  const rerunCommand = defaultTask ? options.trials !== void 0 ? `pome run -n ${k}` : "pome run" : `pome run ${fileForRerun && !fileForRerun.startsWith("..") ? fileForRerun : file} -n ${k}`;
4989
4996
  const groupResult = await runTrialGroup({
@@ -5077,7 +5084,7 @@ function createProgram() {
5077
5084
  process.exitCode = 5;
5078
5085
  return;
5079
5086
  }
5080
- const { runDemo } = await import('../../runDemo-7QCEWKQJ.js');
5087
+ const { runDemo } = await import('../../runDemo-NPBMT4BF.js');
5081
5088
  const result = await runDemo({
5082
5089
  apiBase: opts.apiUrl.replace(/\/$/, ""),
5083
5090
  dashboardBase: process.env.POME_DASHBOARD_URL ?? DEFAULT_DASHBOARD_URL,
@@ -5182,10 +5189,17 @@ function createProgram() {
5182
5189
  }
5183
5190
  const root = target ?? "runs";
5184
5191
  const discovery = await discoverRunSet(resolve(root));
5185
- if (discovery.totalSets === 0) {
5192
+ if (discovery.staleVersionCount > 0) {
5186
5193
  console.error(
5187
- `No finalized run sets under ${root} \u2014 hosted \`pome run\` records a verdict.json per trial; run one first (or point fix-prompt at your artifacts dir).`
5194
+ `${discovery.staleVersionCount} verdict.json file(s) under ${root} are not artifact version ${VERDICT_ARTIFACT_VERSION} (the only version this CLI reads) and were skipped \u2014 re-run \`pome run\` to record those trials again.`
5188
5195
  );
5196
+ }
5197
+ if (discovery.totalSets === 0) {
5198
+ if (discovery.staleVersionCount === 0) {
5199
+ console.error(
5200
+ `No finalized run sets under ${root} \u2014 hosted \`pome run\` records a verdict.json per trial; run one first (or point fix-prompt at your artifacts dir).`
5201
+ );
5202
+ }
5189
5203
  process.exitCode = 5;
5190
5204
  return;
5191
5205
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pome-sh/cli",
3
- "version": "0.23.0",
3
+ "version": "0.23.2",
4
4
  "description": "Digital-twin testing for AI agents \u2014 run tasks against resettable local or hosted twins and record tool-call traces for evaluation on pome.sh.",
5
5
  "keywords": [
6
6
  "ai",