@outcomeeng/spx 0.6.11 → 0.6.13

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 (3) hide show
  1. package/dist/cli.js +1433 -300
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -126,6 +126,7 @@ var AGENT_RESUME_LIMITS = {
126
126
  RECENT_DAYS: 7,
127
127
  PER_AGENT_DISPLAYED_CANDIDATES: 5,
128
128
  METADATA_HEAD_BYTES: 131072,
129
+ ACTIVITY_TAIL_BYTES: 131072,
129
130
  HOURS_PER_DAY: 24,
130
131
  MINUTES_PER_HOUR: 60,
131
132
  SECONDS_PER_MINUTE: 60,
@@ -196,6 +197,10 @@ var FIRST_PICKER_INDEX = 0;
196
197
  var PICKER_MOVE_UP_DELTA = -1;
197
198
  var PICKER_MOVE_DOWN_DELTA = 1;
198
199
  var PICKER_QUIT_INPUT = "q";
200
+ var AGENT_RESUME_TIE_ORDER = {
201
+ [AGENT_SESSION_KIND.CODEX]: 0,
202
+ [AGENT_SESSION_KIND.CLAUDE_CODE]: 1
203
+ };
199
204
  var AgentResumeModeError = class extends Error {
200
205
  constructor(selectedModes) {
201
206
  super(`${AGENT_RESUME_TEXT.MODE_CONFLICT}: ${selectedModes.join(", ")}`);
@@ -314,7 +319,7 @@ function renderAgentResumeList(candidates) {
314
319
  return AGENT_RESUME_TEXT.NO_MATCHES;
315
320
  }
316
321
  return candidates.map((candidate) => {
317
- const updatedAt = candidate.updatedAt ?? new Date(candidate.modifiedAtMs).toISOString();
322
+ const updatedAt = candidate.lastActivityAtMs === null ? "unknown" : new Date(candidate.lastActivityAtMs).toISOString();
318
323
  return `${updatedAt} ${AGENT_SESSION_LABEL[candidate.agent]} ${candidate.sessionId} ${candidate.cwd}`;
319
324
  }).join("\n");
320
325
  }
@@ -340,32 +345,41 @@ async function claudeTranscriptFiles(root, fs8, dirAccepts) {
340
345
  return perDir.flat();
341
346
  }
342
347
  async function collectAgentCandidates(agent, files, fs8, cap, match, parseHead) {
343
- const seen = /* @__PURE__ */ new Set();
344
- const candidates = [];
345
- for (const file of files) {
346
- if (candidates.length >= cap) {
347
- break;
348
- }
348
+ const candidates = await mapWithConcurrency(files, AGENT_RESUME_LIMITS.READ_CONCURRENCY, async (file) => {
349
349
  const head = await fs8.readHead(file.path, AGENT_RESUME_LIMITS.METADATA_HEAD_BYTES).catch(() => null);
350
350
  if (head === null) {
351
- continue;
351
+ return null;
352
352
  }
353
353
  const core = parseHead(head);
354
- if (core === null || !core.interactive || !match(core) || seen.has(core.sessionId)) {
355
- continue;
354
+ if (core === null || !core.interactive || !match(core)) {
355
+ return null;
356
356
  }
357
- seen.add(core.sessionId);
358
- candidates.push({
357
+ const tail = await fs8.readTail(file.path, AGENT_RESUME_LIMITS.ACTIVITY_TAIL_BYTES).catch(() => null);
358
+ if (tail === null) {
359
+ return null;
360
+ }
361
+ return {
359
362
  agent,
360
363
  sessionId: core.sessionId,
361
364
  cwd: core.cwd,
362
365
  sourcePath: file.path,
363
366
  modifiedAtMs: file.modifiedAtMs,
367
+ lastActivityAtMs: latestTranscriptTimestampMs(tail),
364
368
  updatedAt: core.updatedAt,
365
369
  branch: core.branch
366
- });
370
+ };
371
+ });
372
+ const bySessionId = /* @__PURE__ */ new Map();
373
+ for (const candidate of candidates) {
374
+ if (candidate === null) {
375
+ continue;
376
+ }
377
+ const existing = bySessionId.get(candidate.sessionId);
378
+ if (existing === void 0 || compareCandidates(candidate, existing) < 0) {
379
+ bySessionId.set(candidate.sessionId, candidate);
380
+ }
367
381
  }
368
- return candidates;
382
+ return [...bySessionId.values()].sort(compareCandidates).slice(0, cap);
369
383
  }
370
384
  async function collectJsonlFiles(root, fs8) {
371
385
  const entries = await fs8.readDir(root).catch(() => []);
@@ -475,6 +489,27 @@ function parseJsonObject(line) {
475
489
  return null;
476
490
  }
477
491
  }
492
+ function latestTranscriptTimestampMs(transcriptSlice) {
493
+ let latest = null;
494
+ for (const line of transcriptSlice.split("\n")) {
495
+ const row = parseJsonObject(line);
496
+ if (row === null) {
497
+ continue;
498
+ }
499
+ const timestampMs = parseTimestampMs(firstString(row, [[AGENT_SESSION_JSON_FIELDS.TIMESTAMP]]));
500
+ if (timestampMs !== null && (latest === null || timestampMs > latest)) {
501
+ latest = timestampMs;
502
+ }
503
+ }
504
+ return latest;
505
+ }
506
+ function parseTimestampMs(timestamp) {
507
+ if (timestamp === null) {
508
+ return null;
509
+ }
510
+ const timestampMs = Date.parse(timestamp);
511
+ return Number.isNaN(timestampMs) ? null : timestampMs;
512
+ }
478
513
  function firstString(row, paths) {
479
514
  for (const path7 of paths) {
480
515
  const value = valueAtPath(row, path7);
@@ -498,11 +533,30 @@ function isRecord(value) {
498
533
  return typeof value === "object" && value !== null && !Array.isArray(value);
499
534
  }
500
535
  function compareCandidates(left, right) {
501
- const modifiedDiff = right.modifiedAtMs - left.modifiedAtMs;
502
- if (modifiedDiff !== 0) {
503
- return modifiedDiff;
536
+ if (left.lastActivityAtMs !== null && right.lastActivityAtMs !== null) {
537
+ const activityDiff = right.lastActivityAtMs - left.lastActivityAtMs;
538
+ if (activityDiff !== 0) {
539
+ return activityDiff;
540
+ }
541
+ } else if (left.lastActivityAtMs !== null) {
542
+ return -1;
543
+ } else if (right.lastActivityAtMs !== null) {
544
+ return 1;
504
545
  }
505
- return `${left.agent}:${left.sessionId}`.localeCompare(`${right.agent}:${right.sessionId}`);
546
+ const agentDiff = AGENT_RESUME_TIE_ORDER[left.agent] - AGENT_RESUME_TIE_ORDER[right.agent];
547
+ if (agentDiff !== 0) {
548
+ return agentDiff;
549
+ }
550
+ return compareCodeUnits(`${left.sessionId}:${left.sourcePath}`, `${right.sessionId}:${right.sourcePath}`);
551
+ }
552
+ function compareCodeUnits(left, right) {
553
+ if (left < right) {
554
+ return -1;
555
+ }
556
+ if (left > right) {
557
+ return 1;
558
+ }
559
+ return 0;
506
560
  }
507
561
  function isPathInsideOrEqual(parent, child) {
508
562
  const rel = relative(resolve3(parent), resolve3(child));
@@ -1094,6 +1148,19 @@ var nodeAgentSessionFileSystem = {
1094
1148
  await handle.close();
1095
1149
  }
1096
1150
  },
1151
+ async readTail(path7, maxBytes) {
1152
+ const fileStat = await stat(path7);
1153
+ const bytesToRead = Math.min(maxBytes, fileStat.size);
1154
+ const start = Math.max(0, fileStat.size - bytesToRead);
1155
+ const handle = await open(path7, "r");
1156
+ try {
1157
+ const buffer = Buffer.alloc(bytesToRead);
1158
+ const { bytesRead } = await handle.read(buffer, 0, bytesToRead, start);
1159
+ return buffer.toString(AGENT_SESSION_STORE.TEXT_ENCODING, 0, bytesRead);
1160
+ } finally {
1161
+ await handle.close();
1162
+ }
1163
+ },
1097
1164
  async stat(path7) {
1098
1165
  const result = await stat(path7);
1099
1166
  return { mtimeMs: result.mtimeMs };
@@ -1787,6 +1854,7 @@ import {
1787
1854
  mkdir as nodeMkdir,
1788
1855
  open as nodeOpen,
1789
1856
  readdir as nodeReaddir,
1857
+ rename as nodeRename,
1790
1858
  rm as nodeRm
1791
1859
  } from "fs/promises";
1792
1860
  import { dirname as dirname2, join as join2 } from "path";
@@ -1880,6 +1948,9 @@ var defaultFileSystem = {
1880
1948
  },
1881
1949
  readdir: nodeReaddir,
1882
1950
  lstat: nodeLstat,
1951
+ rename: async (from, to) => {
1952
+ await nodeRename(from, to);
1953
+ },
1883
1954
  rm: async (path7, options) => {
1884
1955
  await nodeRm(path7, options);
1885
1956
  }
@@ -1972,8 +2043,8 @@ function formatRunTimestamp(date) {
1972
2043
  );
1973
2044
  return `${year}-${month}-${day}${RUN_TIMESTAMP_SEPARATOR}${hours}-${minutes}-${seconds}-${milliseconds}`;
1974
2045
  }
1975
- function generateRunId(randomBytes2 = nodeRandomBytes) {
1976
- return randomBytes2(STATE_STORE_RUN_TOKEN.ID_BYTES).toString(HEX_ENCODING);
2046
+ function generateRunId(randomBytes3 = nodeRandomBytes) {
2047
+ return randomBytes3(STATE_STORE_RUN_TOKEN.ID_BYTES).toString(HEX_ENCODING);
1977
2048
  }
1978
2049
  function createStateStoreRunToken(options) {
1979
2050
  const startedAt = formatRunTimestamp(options.date);
@@ -1995,7 +2066,7 @@ async function createJsonlRunFile(scopeDir, domainName, options = {}) {
1995
2066
  if (!domainRunsDir.ok) return domainRunsDir;
1996
2067
  const maxAttempts = options.maxAttempts ?? RUN_FILE_CREATE_ATTEMPTS;
1997
2068
  const startedDate = (options.now ?? (() => /* @__PURE__ */ new Date()))();
1998
- const randomBytes2 = options.randomBytes ?? nodeRandomBytes;
2069
+ const randomBytes3 = options.randomBytes ?? nodeRandomBytes;
1999
2070
  try {
2000
2071
  await fs8.mkdir(domainRunsDir.value, { recursive: true });
2001
2072
  } catch (error) {
@@ -2005,7 +2076,7 @@ async function createJsonlRunFile(scopeDir, domainName, options = {}) {
2005
2076
  };
2006
2077
  }
2007
2078
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
2008
- const token = createStateStoreRunToken({ date: startedDate, randomBytes: randomBytes2 });
2079
+ const token = createStateStoreRunToken({ date: startedDate, randomBytes: randomBytes3 });
2009
2080
  const name = runFileName(token.runToken);
2010
2081
  const path7 = join2(domainRunsDir.value, name);
2011
2082
  try {
@@ -2528,8 +2599,8 @@ import path2 from "path";
2528
2599
  // src/lib/atomic-file-write.ts
2529
2600
  var TEMP_TOKEN_BYTES = 8;
2530
2601
  var TEMP_SUFFIX = ".tmp";
2531
- function atomicWriteTempPath(targetPath, randomBytes2) {
2532
- const token = randomBytes2(TEMP_TOKEN_BYTES).toString("hex");
2602
+ function atomicWriteTempPath(targetPath, randomBytes3) {
2603
+ const token = randomBytes3(TEMP_TOKEN_BYTES).toString("hex");
2533
2604
  return `${targetPath}.${token}${TEMP_SUFFIX}`;
2534
2605
  }
2535
2606
  async function writeFileAtomic(targetPath, content, options) {
@@ -3010,6 +3081,7 @@ var AGENT = {
3010
3081
  CLAUDE_CODE: "claudeCode"
3011
3082
  };
3012
3083
  var HARNESS_ENVIRONMENT_CONFIG_FIELDS = {
3084
+ METHODOLOGY: "methodology",
3013
3085
  INSTRUCTIONS: "instructions",
3014
3086
  AGENTS: "agents",
3015
3087
  PLUGIN_BOOTSTRAP: "pluginBootstrap",
@@ -3029,6 +3101,8 @@ var HARNESS_ENVIRONMENT_CONFIG_FIELDS = {
3029
3101
  VERSION: "version",
3030
3102
  MARKETPLACE: "marketplace"
3031
3103
  };
3104
+ var DEFAULT_METHODOLOGY_SOURCE = "outcomeeng/spec-tree";
3105
+ var DEFAULT_METHODOLOGY_VERSION = "installed";
3032
3106
  var AGENT_SET = new Set(Object.values(AGENT));
3033
3107
  var DEFAULT_AGENT_INSTRUCTION_TARGET_AGENTS = [
3034
3108
  AGENT.CODEX,
@@ -3036,6 +3110,10 @@ var DEFAULT_AGENT_INSTRUCTION_TARGET_AGENTS = [
3036
3110
  ];
3037
3111
  var DEFAULT_AGENT_INSTRUCTION_FILE_PATH = "AGENTS.md";
3038
3112
  var DEFAULT_HARNESS_ENVIRONMENT_CONFIG = {
3113
+ methodology: {
3114
+ source: DEFAULT_METHODOLOGY_SOURCE,
3115
+ version: DEFAULT_METHODOLOGY_VERSION
3116
+ },
3039
3117
  instructions: {
3040
3118
  files: [
3041
3119
  {
@@ -3069,10 +3147,15 @@ var DEFAULT_HARNESS_ENVIRONMENT_CONFIG = {
3069
3147
  }
3070
3148
  };
3071
3149
  var HARNESS_ENVIRONMENT_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
3150
+ HARNESS_ENVIRONMENT_CONFIG_FIELDS.METHODOLOGY,
3072
3151
  HARNESS_ENVIRONMENT_CONFIG_FIELDS.INSTRUCTIONS,
3073
3152
  HARNESS_ENVIRONMENT_CONFIG_FIELDS.AGENTS,
3074
3153
  HARNESS_ENVIRONMENT_CONFIG_FIELDS.PLUGIN_BOOTSTRAP
3075
3154
  ]);
3155
+ var HARNESS_ENVIRONMENT_METHODOLOGY_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
3156
+ HARNESS_ENVIRONMENT_CONFIG_FIELDS.SOURCE,
3157
+ HARNESS_ENVIRONMENT_CONFIG_FIELDS.VERSION
3158
+ ]);
3076
3159
  var HARNESS_ENVIRONMENT_INSTRUCTIONS_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
3077
3160
  HARNESS_ENVIRONMENT_CONFIG_FIELDS.FILES
3078
3161
  ]);
@@ -3137,6 +3220,21 @@ function validateBoolean(path7, value) {
3137
3220
  }
3138
3221
  return { ok: true, value };
3139
3222
  }
3223
+ function validateMethodology(raw) {
3224
+ const sectionPath = `${HARNESS_ENVIRONMENT_SECTION}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.METHODOLOGY}`;
3225
+ if (!isRecord2(raw)) {
3226
+ return { ok: false, error: `${sectionPath} must be an object` };
3227
+ }
3228
+ const unknown = rejectUnknownFields(sectionPath, raw, HARNESS_ENVIRONMENT_METHODOLOGY_ALLOWED_FIELDS);
3229
+ if (!unknown.ok) return unknown;
3230
+ const sourceRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.SOURCE];
3231
+ const source = sourceRaw === void 0 ? { ok: true, value: DEFAULT_HARNESS_ENVIRONMENT_CONFIG.methodology.source } : validateNonEmptyString(`${sectionPath}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.SOURCE}`, sourceRaw);
3232
+ if (!source.ok) return source;
3233
+ const versionRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.VERSION];
3234
+ const version2 = versionRaw === void 0 ? { ok: true, value: DEFAULT_HARNESS_ENVIRONMENT_CONFIG.methodology.version } : validateNonEmptyString(`${sectionPath}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.VERSION}`, versionRaw);
3235
+ if (!version2.ok) return version2;
3236
+ return { ok: true, value: { source: source.value, version: version2.value } };
3237
+ }
3140
3238
  function validateAgent(path7, value) {
3141
3239
  if (typeof value !== "string" || !isAgent(value)) {
3142
3240
  return { ok: false, error: `${path7} must be a registered agent` };
@@ -3223,37 +3321,37 @@ function validateAgents(raw) {
3223
3321
  }
3224
3322
  return { ok: true, value: agents };
3225
3323
  }
3226
- function validateAgentConfig(path7, raw, defaults5) {
3324
+ function validateAgentConfig(path7, raw, defaults6) {
3227
3325
  if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
3228
3326
  const unknown = rejectUnknownFields(path7, raw, HARNESS_ENVIRONMENT_AGENT_CONFIG_ALLOWED_FIELDS);
3229
3327
  if (!unknown.ok) return unknown;
3230
3328
  const enabledRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.ENABLED];
3231
- const enabled = enabledRaw === void 0 ? { ok: true, value: defaults5.enabled } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.ENABLED}`, enabledRaw);
3329
+ const enabled = enabledRaw === void 0 ? { ok: true, value: defaults6.enabled } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.ENABLED}`, enabledRaw);
3232
3330
  if (!enabled.ok) return enabled;
3233
3331
  const hooksRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.HOOKS];
3234
- const hooks = hooksRaw === void 0 ? { ok: true, value: defaults5.hooks } : validateAgentHooks(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.HOOKS}`, hooksRaw, defaults5.hooks);
3332
+ const hooks = hooksRaw === void 0 ? { ok: true, value: defaults6.hooks } : validateAgentHooks(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.HOOKS}`, hooksRaw, defaults6.hooks);
3235
3333
  if (!hooks.ok) return hooks;
3236
3334
  return { ok: true, value: { enabled: enabled.value, hooks: hooks.value } };
3237
3335
  }
3238
- function validateAgentHooks(path7, raw, defaults5) {
3336
+ function validateAgentHooks(path7, raw, defaults6) {
3239
3337
  if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
3240
3338
  const unknown = rejectUnknownFields(path7, raw, HARNESS_ENVIRONMENT_AGENT_HOOKS_ALLOWED_FIELDS);
3241
3339
  if (!unknown.ok) return unknown;
3242
3340
  const sessionStartRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.SESSION_START];
3243
- const sessionStart = sessionStartRaw === void 0 ? { ok: true, value: defaults5.sessionStart } : validateSessionStartHooks(
3341
+ const sessionStart = sessionStartRaw === void 0 ? { ok: true, value: defaults6.sessionStart } : validateSessionStartHooks(
3244
3342
  `${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.SESSION_START}`,
3245
3343
  sessionStartRaw,
3246
- defaults5.sessionStart
3344
+ defaults6.sessionStart
3247
3345
  );
3248
3346
  if (!sessionStart.ok) return sessionStart;
3249
3347
  return { ok: true, value: { sessionStart: sessionStart.value } };
3250
3348
  }
3251
- function validateSessionStartHooks(path7, raw, defaults5) {
3349
+ function validateSessionStartHooks(path7, raw, defaults6) {
3252
3350
  if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
3253
3351
  const unknown = rejectUnknownFields(path7, raw, HARNESS_ENVIRONMENT_SESSION_START_HOOKS_ALLOWED_FIELDS);
3254
3352
  if (!unknown.ok) return unknown;
3255
3353
  const compactStdoutRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.COMPACT_STDOUT];
3256
- const compactStdout = compactStdoutRaw === void 0 ? { ok: true, value: defaults5.compactStdout } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.COMPACT_STDOUT}`, compactStdoutRaw);
3354
+ const compactStdout = compactStdoutRaw === void 0 ? { ok: true, value: defaults6.compactStdout } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.COMPACT_STDOUT}`, compactStdoutRaw);
3257
3355
  if (!compactStdout.ok) return compactStdout;
3258
3356
  return { ok: true, value: { compactStdout: compactStdout.value } };
3259
3357
  }
@@ -3326,8 +3424,8 @@ function validatePluginBootstrap(raw) {
3326
3424
  }
3327
3425
  };
3328
3426
  }
3329
- function validateEntryArray(path7, raw, validateEntry, defaults5) {
3330
- if (raw === void 0) return { ok: true, value: defaults5 };
3427
+ function validateEntryArray(path7, raw, validateEntry, defaults6) {
3428
+ if (raw === void 0) return { ok: true, value: defaults6 };
3331
3429
  if (!Array.isArray(raw)) return { ok: false, error: `${path7} must be an array` };
3332
3430
  const entries = [];
3333
3431
  for (const [index, entry] of raw.entries()) {
@@ -3518,6 +3616,9 @@ function validate(value) {
3518
3616
  HARNESS_ENVIRONMENT_ALLOWED_FIELDS
3519
3617
  );
3520
3618
  if (!unknown.ok) return unknown;
3619
+ const methodologyRaw = value[HARNESS_ENVIRONMENT_CONFIG_FIELDS.METHODOLOGY];
3620
+ const methodology = methodologyRaw === void 0 ? { ok: true, value: DEFAULT_HARNESS_ENVIRONMENT_CONFIG.methodology } : validateMethodology(methodologyRaw);
3621
+ if (!methodology.ok) return methodology;
3521
3622
  const instructionsRaw = value[HARNESS_ENVIRONMENT_CONFIG_FIELDS.INSTRUCTIONS];
3522
3623
  const instructions = instructionsRaw === void 0 ? { ok: true, value: DEFAULT_HARNESS_ENVIRONMENT_CONFIG.instructions } : validateInstructions(instructionsRaw);
3523
3624
  if (!instructions.ok) return instructions;
@@ -3530,6 +3631,7 @@ function validate(value) {
3530
3631
  return {
3531
3632
  ok: true,
3532
3633
  value: {
3634
+ methodology: methodology.value,
3533
3635
  instructions: instructions.value,
3534
3636
  agents: agents.value,
3535
3637
  pluginBootstrap: pluginBootstrap.value
@@ -3618,6 +3720,36 @@ var diagnoseConfigDescriptor = {
3618
3720
  validate: validate2
3619
3721
  };
3620
3722
 
3723
+ // src/lib/agent-run-journal/config.ts
3724
+ var RUNTIME_SECTION = "runtime";
3725
+ var RUNTIME_CONFIG_FIELDS = {
3726
+ EVENT_NAMESPACE: "eventNamespace"
3727
+ };
3728
+ var RUNTIME_EVENT_NAMESPACE_DEFAULT = "sh.spx";
3729
+ var defaults2 = { eventNamespace: RUNTIME_EVENT_NAMESPACE_DEFAULT };
3730
+ function validate3(value) {
3731
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3732
+ return { ok: false, error: `${RUNTIME_SECTION} section must be an object` };
3733
+ }
3734
+ const candidate = value;
3735
+ const raw = candidate[RUNTIME_CONFIG_FIELDS.EVENT_NAMESPACE];
3736
+ if (raw === void 0) {
3737
+ return { ok: true, value: { eventNamespace: RUNTIME_EVENT_NAMESPACE_DEFAULT } };
3738
+ }
3739
+ if (typeof raw !== "string" || raw.trim().length === 0) {
3740
+ return {
3741
+ ok: false,
3742
+ error: `${RUNTIME_SECTION}.${RUNTIME_CONFIG_FIELDS.EVENT_NAMESPACE} must be a non-empty string`
3743
+ };
3744
+ }
3745
+ return { ok: true, value: { eventNamespace: raw } };
3746
+ }
3747
+ var runtimeConfigDescriptor = {
3748
+ section: RUNTIME_SECTION,
3749
+ defaults: defaults2,
3750
+ validate: validate3
3751
+ };
3752
+
3621
3753
  // src/lib/file-inclusion/adapters/eslint.ts
3622
3754
  function eslintAdapter(scope2, config) {
3623
3755
  return scope2.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);
@@ -3678,7 +3810,7 @@ var DEFAULT_SCOPE_CONFIG = {};
3678
3810
  var DEFAULT_TOOLS_CONFIG = Object.fromEntries(
3679
3811
  Object.entries(TOOL_DEFAULT_FLAGS).map(([name, flag]) => [name, { ignoreFlag: flag }])
3680
3812
  );
3681
- var defaults2 = {
3813
+ var defaults3 = {
3682
3814
  scope: DEFAULT_SCOPE_CONFIG,
3683
3815
  tools: DEFAULT_TOOLS_CONFIG
3684
3816
  };
@@ -3750,7 +3882,7 @@ function validateTools(raw) {
3750
3882
  }
3751
3883
  return { ok: true, value: tools };
3752
3884
  }
3753
- function validate3(value) {
3885
+ function validate4(value) {
3754
3886
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
3755
3887
  return { ok: false, error: `${FILE_INCLUSION_SECTION} section must be an object` };
3756
3888
  }
@@ -3777,60 +3909,7 @@ function validate3(value) {
3777
3909
  }
3778
3910
  var fileInclusionConfigDescriptor = {
3779
3911
  section: FILE_INCLUSION_SECTION,
3780
- defaults: defaults2,
3781
- validate: validate3
3782
- };
3783
-
3784
- // src/config/source-roots.ts
3785
- var TEST_RELEVANT_SOURCE_ROOT_PREFIX = {
3786
- SOURCE: "src/",
3787
- TESTING: "testing/",
3788
- SCRIPTS: "scripts/",
3789
- ESLINT_RULES: "eslint-rules/"
3790
- };
3791
- var TEST_RELEVANT_SOURCE_ROOT_PREFIXES = [
3792
- TEST_RELEVANT_SOURCE_ROOT_PREFIX.SOURCE,
3793
- TEST_RELEVANT_SOURCE_ROOT_PREFIX.TESTING,
3794
- TEST_RELEVANT_SOURCE_ROOT_PREFIX.SCRIPTS,
3795
- TEST_RELEVANT_SOURCE_ROOT_PREFIX.ESLINT_RULES
3796
- ];
3797
-
3798
- // src/lib/precommit/config.ts
3799
- var PRECOMMIT_SECTION = "precommit";
3800
- var PRECOMMIT_DEFAULTS = {
3801
- sourceDirs: TEST_RELEVANT_SOURCE_ROOT_PREFIXES,
3802
- testPattern: ".test.ts"
3803
- };
3804
- function validate4(value) {
3805
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
3806
- return { ok: false, error: `${PRECOMMIT_SECTION} section must be an object` };
3807
- }
3808
- const candidate = value;
3809
- const sourceDirs = candidate["sourceDirs"] ?? PRECOMMIT_DEFAULTS.sourceDirs;
3810
- if (!Array.isArray(sourceDirs) || !sourceDirs.every((x) => typeof x === "string" && x.length > 0)) {
3811
- return {
3812
- ok: false,
3813
- error: `${PRECOMMIT_SECTION}.sourceDirs must be a non-empty array of non-empty strings`
3814
- };
3815
- }
3816
- const testPattern = candidate["testPattern"] ?? PRECOMMIT_DEFAULTS.testPattern;
3817
- if (typeof testPattern !== "string" || testPattern.length === 0) {
3818
- return {
3819
- ok: false,
3820
- error: `${PRECOMMIT_SECTION}.testPattern must be a non-empty string`
3821
- };
3822
- }
3823
- return {
3824
- ok: true,
3825
- value: {
3826
- sourceDirs,
3827
- testPattern
3828
- }
3829
- };
3830
- }
3831
- var precommitConfigDescriptor = {
3832
- section: PRECOMMIT_SECTION,
3833
- defaults: PRECOMMIT_DEFAULTS,
3912
+ defaults: defaults3,
3834
3913
  validate: validate4
3835
3914
  };
3836
3915
 
@@ -4194,7 +4273,7 @@ var TESTING_CONFIG_FIELDS = {
4194
4273
  PASSING_SCOPE: "passingScope"
4195
4274
  };
4196
4275
  var DEFAULT_PASSING_SCOPE = resolveDefaultPassingScope();
4197
- var defaults3 = {
4276
+ var defaults4 = {
4198
4277
  passingScope: DEFAULT_PASSING_SCOPE
4199
4278
  };
4200
4279
  function resolveDefaultPassingScope() {
@@ -4214,7 +4293,7 @@ function validate6(value) {
4214
4293
  const candidate = value;
4215
4294
  const passingScopeRaw = candidate[TESTING_CONFIG_FIELDS.PASSING_SCOPE];
4216
4295
  if (passingScopeRaw === void 0) {
4217
- return { ok: true, value: defaults3 };
4296
+ return { ok: true, value: defaults4 };
4218
4297
  }
4219
4298
  const passingScopeResult = validatePathFilterConfig(
4220
4299
  passingScopeRaw,
@@ -4230,7 +4309,7 @@ function validate6(value) {
4230
4309
  }
4231
4310
  var testingConfigDescriptor = {
4232
4311
  section: TESTING_SECTION,
4233
- defaults: defaults3,
4312
+ defaults: defaults4,
4234
4313
  validate: validate6
4235
4314
  };
4236
4315
 
@@ -4378,7 +4457,7 @@ var VALIDATION_PATH_TOOL_SUBSECTIONS = {
4378
4457
  LITERAL: "literal",
4379
4458
  FORMATTING: "formatting"
4380
4459
  };
4381
- var defaults4 = {
4460
+ var defaults5 = {
4382
4461
  paths: {},
4383
4462
  literal: {
4384
4463
  enabled: true,
@@ -4418,7 +4497,7 @@ function validateLiteral(raw) {
4418
4497
  };
4419
4498
  }
4420
4499
  const candidate = raw;
4421
- const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults4.literal.enabled;
4500
+ const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults5.literal.enabled;
4422
4501
  if (typeof enabledRaw !== "boolean") {
4423
4502
  return {
4424
4503
  ok: false,
@@ -4443,7 +4522,7 @@ function validateKnip(raw) {
4443
4522
  };
4444
4523
  }
4445
4524
  const candidate = raw;
4446
- const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults4.knip.enabled;
4525
+ const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults5.knip.enabled;
4447
4526
  if (typeof enabledRaw !== "boolean") {
4448
4527
  return {
4449
4528
  ok: false,
@@ -4470,7 +4549,7 @@ function validate8(value) {
4470
4549
  }
4471
4550
  var validationConfigDescriptor = {
4472
4551
  section: VALIDATION_SECTION,
4473
- defaults: defaults4,
4552
+ defaults: defaults5,
4474
4553
  validate: validate8
4475
4554
  };
4476
4555
 
@@ -4480,17 +4559,17 @@ var productionRegistry = [
4480
4559
  validationConfigDescriptor,
4481
4560
  testingConfigDescriptor,
4482
4561
  fileInclusionConfigDescriptor,
4483
- precommitConfigDescriptor,
4484
4562
  harnessEnvironmentConfigDescriptor,
4485
- diagnoseConfigDescriptor
4563
+ diagnoseConfigDescriptor,
4564
+ runtimeConfigDescriptor
4486
4565
  ];
4487
4566
 
4488
4567
  // src/config/descriptor-digest.ts
4489
4568
  import { createHash as createHash3 } from "crypto";
4490
4569
  var DEFAULT_DESCRIPTOR_PATH = "descriptor section";
4491
- var SHA256_ALGORITHM2 = "sha256";
4570
+ var DESCRIPTOR_DIGEST_SHA256_ALGORITHM = "sha256";
4492
4571
  var UTF8_ENCODING2 = "utf8";
4493
- var HEX_ENCODING2 = "hex";
4572
+ var DESCRIPTOR_DIGEST_HEX_ENCODING = "hex";
4494
4573
  function canonicalDescriptorJson(value, path7 = DEFAULT_DESCRIPTOR_PATH) {
4495
4574
  const normalized = normalizeDescriptorJsonValue(value, path7, /* @__PURE__ */ new WeakSet());
4496
4575
  if (!normalized.ok) return normalized;
@@ -4499,7 +4578,7 @@ function canonicalDescriptorJson(value, path7 = DEFAULT_DESCRIPTOR_PATH) {
4499
4578
  function digestDescriptorSection(value, path7 = DEFAULT_DESCRIPTOR_PATH) {
4500
4579
  const canonical = canonicalDescriptorJson(value, path7);
4501
4580
  if (!canonical.ok) return canonical;
4502
- const sha256 = createHash3(SHA256_ALGORITHM2).update(Buffer.from(canonical.value, UTF8_ENCODING2)).digest(HEX_ENCODING2);
4581
+ const sha256 = createHash3(DESCRIPTOR_DIGEST_SHA256_ALGORITHM).update(Buffer.from(canonical.value, UTF8_ENCODING2)).digest(DESCRIPTOR_DIGEST_HEX_ENCODING);
4503
4582
  return {
4504
4583
  ok: true,
4505
4584
  value: {
@@ -6242,7 +6321,7 @@ import {
6242
6321
  mkdir as nodeMkdir2,
6243
6322
  readFile as nodeReadFile,
6244
6323
  readlink as nodeReadlink,
6245
- rename as nodeRename,
6324
+ rename as nodeRename2,
6246
6325
  rm as nodeRm2,
6247
6326
  symlink as nodeSymlink,
6248
6327
  writeFile as nodeWriteFile
@@ -6254,7 +6333,7 @@ var defaultOccupancyFileSystem = {
6254
6333
  writeFile: async (path7, data) => {
6255
6334
  await nodeWriteFile(path7, data);
6256
6335
  },
6257
- rename: nodeRename,
6336
+ rename: nodeRename2,
6258
6337
  symlink: nodeSymlink,
6259
6338
  readlink: nodeReadlink,
6260
6339
  readFile: nodeReadFile,
@@ -7145,9 +7224,9 @@ var JOURNAL_RUN_STATE_INCOMPLETE_REASON = {
7145
7224
  };
7146
7225
  var JOURNAL_RUN_EVENT = {
7147
7226
  SOURCE: "/spx/journal",
7148
- STARTED_TYPE: "com.outcomeeng.spx.journal.run.started",
7149
- PROGRESS_TYPE: "com.outcomeeng.spx.journal.run.progress",
7150
- COMPLETED_TYPE: "com.outcomeeng.spx.journal.run.completed"
7227
+ STARTED_TYPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.journal.run.started`,
7228
+ PROGRESS_TYPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.journal.run.progress`,
7229
+ COMPLETED_TYPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.journal.run.completed`
7151
7230
  };
7152
7231
  var JOURNAL_RUN_STATE_FIELDS = {
7153
7232
  BRANCH_NAME: "branchName",
@@ -7166,13 +7245,18 @@ var JOURNAL_RUN_STATE_FIELDS = {
7166
7245
  STATUS: "status"
7167
7246
  };
7168
7247
  function foldJournalRunState(events, sealed) {
7169
- if (!sealed) return { ok: false, reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.UNSEALED };
7248
+ if (!sealed) {
7249
+ return { ok: false, reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.UNSEALED };
7250
+ }
7170
7251
  let completed;
7171
7252
  for (const event of events) {
7172
7253
  if (event.type === JOURNAL_RUN_EVENT.COMPLETED_TYPE) completed = event;
7173
7254
  }
7174
7255
  if (completed === void 0) {
7175
- return { ok: false, reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.MISSING_STATE };
7256
+ return {
7257
+ ok: false,
7258
+ reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.MISSING_STATE
7259
+ };
7176
7260
  }
7177
7261
  const validated = validateJournalRunState(completed.data);
7178
7262
  if (!validated.ok) {
@@ -7185,13 +7269,17 @@ function foldJournalRunState(events, sealed) {
7185
7269
  return validated;
7186
7270
  }
7187
7271
  function isJournalRunStateStatus(value) {
7188
- return typeof value === "string" && Object.values(JOURNAL_RUN_STATE_STATUS).includes(value);
7272
+ return typeof value === "string" && Object.values(JOURNAL_RUN_STATE_STATUS).includes(
7273
+ value
7274
+ );
7189
7275
  }
7190
7276
  function isJournalTargetKind(value) {
7191
7277
  return typeof value === "string" && Object.values(JOURNAL_TARGET_KIND).includes(value);
7192
7278
  }
7193
7279
  function validateJournalRunState(value) {
7194
- if (!isRecord5(value)) return { ok: false, error: "journal run state must be an object" };
7280
+ if (!isRecord5(value)) {
7281
+ return { ok: false, error: "journal run state must be an object" };
7282
+ }
7195
7283
  const identity = readRunStateIdentity(value);
7196
7284
  if (!identity.ok) return identity;
7197
7285
  const body = readRunStateBody(value);
@@ -7203,9 +7291,15 @@ function readRunStateIdentity(value) {
7203
7291
  if (!branchName.ok) return branchName;
7204
7292
  const branchSlug = readString(value, JOURNAL_RUN_STATE_FIELDS.BRANCH_SLUG);
7205
7293
  if (!branchSlug.ok) return branchSlug;
7206
- const targetKind = readTargetKind(value, JOURNAL_RUN_STATE_FIELDS.TARGET_KIND);
7294
+ const targetKind = readTargetKind(
7295
+ value,
7296
+ JOURNAL_RUN_STATE_FIELDS.TARGET_KIND
7297
+ );
7207
7298
  if (!targetKind.ok) return targetKind;
7208
- const pullRequestNumber = readOptionalNonNegativeInteger(value, JOURNAL_RUN_STATE_FIELDS.PULL_REQUEST_NUMBER);
7299
+ const pullRequestNumber = readOptionalNonNegativeInteger(
7300
+ value,
7301
+ JOURNAL_RUN_STATE_FIELDS.PULL_REQUEST_NUMBER
7302
+ );
7209
7303
  if (!pullRequestNumber.ok) return pullRequestNumber;
7210
7304
  const headSha = readString(value, JOURNAL_RUN_STATE_FIELDS.HEAD_SHA);
7211
7305
  if (!headSha.ok) return headSha;
@@ -7227,9 +7321,15 @@ function readRunStateIdentity(value) {
7227
7321
  };
7228
7322
  }
7229
7323
  function readRunStateBody(value) {
7230
- const configDigest = readString(value, JOURNAL_RUN_STATE_FIELDS.CONFIG_DIGEST);
7324
+ const configDigest = readString(
7325
+ value,
7326
+ JOURNAL_RUN_STATE_FIELDS.CONFIG_DIGEST
7327
+ );
7231
7328
  if (!configDigest.ok) return configDigest;
7232
- const participants = readStringArray(value, JOURNAL_RUN_STATE_FIELDS.PARTICIPANTS);
7329
+ const participants = readStringArray(
7330
+ value,
7331
+ JOURNAL_RUN_STATE_FIELDS.PARTICIPANTS
7332
+ );
7233
7333
  if (!participants.ok) return participants;
7234
7334
  const scope2 = readPathFilter(value, JOURNAL_RUN_STATE_FIELDS.SCOPE);
7235
7335
  if (!scope2.ok) return scope2;
@@ -7237,7 +7337,10 @@ function readRunStateBody(value) {
7237
7337
  if (!startedAt.ok) return startedAt;
7238
7338
  const completedAt = readString(value, JOURNAL_RUN_STATE_FIELDS.COMPLETED_AT);
7239
7339
  if (!completedAt.ok) return completedAt;
7240
- const outputPaths = readStringArray(value, JOURNAL_RUN_STATE_FIELDS.OUTPUT_PATHS);
7340
+ const outputPaths = readStringArray(
7341
+ value,
7342
+ JOURNAL_RUN_STATE_FIELDS.OUTPUT_PATHS
7343
+ );
7241
7344
  if (!outputPaths.ok) return outputPaths;
7242
7345
  const status = readStatus(value, JOURNAL_RUN_STATE_FIELDS.STATUS);
7243
7346
  if (!status.ok) return status;
@@ -7266,7 +7369,10 @@ function readOptionalString(value, field) {
7266
7369
  function readOptionalNonNegativeInteger(value, field) {
7267
7370
  const raw = value[field];
7268
7371
  if (raw === void 0) return { ok: true, value: void 0 };
7269
- return typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? { ok: true, value: raw } : { ok: false, error: `${field} must be a non-negative integer when present` };
7372
+ return typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? { ok: true, value: raw } : {
7373
+ ok: false,
7374
+ error: `${field} must be a non-negative integer when present`
7375
+ };
7270
7376
  }
7271
7377
  function readStringArray(value, field) {
7272
7378
  const raw = value[field];
@@ -7508,6 +7614,7 @@ function createJournal(backend, identity) {
7508
7614
 
7509
7615
  // src/lib/appendable-journal-store/index.ts
7510
7616
  var SEAL_MARKER_SUFFIX = ".sealed";
7617
+ var APPENDABLE_JOURNAL_SEAL_MARKER_CONTENT = "";
7511
7618
  var LINE_SEPARATOR3 = "\n";
7512
7619
  function appendableJournalSealMarkerPath(runFilePath) {
7513
7620
  return `${runFilePath}${SEAL_MARKER_SUFFIX}`;
@@ -7547,7 +7654,7 @@ function createAppendableJournalStore(options) {
7547
7654
  readAll,
7548
7655
  async seal() {
7549
7656
  await fs8.mkdir(dirname5(sealMarkerPath), { recursive: true });
7550
- await fs8.writeFile(sealMarkerPath, "");
7657
+ await fs8.writeFile(sealMarkerPath, APPENDABLE_JOURNAL_SEAL_MARKER_CONTENT);
7551
7658
  },
7552
7659
  async isSealed() {
7553
7660
  return await readFileOrUndefined(fs8, sealMarkerPath) !== void 0;
@@ -8004,6 +8111,20 @@ async function sealJournalRun(ref, options = {}) {
8004
8111
  return { ok: false, error: `${JOURNAL_RUNTIME_ERROR.SEAL_FAILED}: ${toMessage(error)}` };
8005
8112
  }
8006
8113
  }
8114
+ async function isJournalRunSealed(ref, options = {}) {
8115
+ const runFilePath = bindRunFilePath(ref);
8116
+ if (!runFilePath.ok) return runFilePath;
8117
+ const fs8 = options.fs ?? defaultFileSystem;
8118
+ if (!await runFileExists(fs8, runFilePath.value)) {
8119
+ return { ok: false, error: JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND };
8120
+ }
8121
+ const store = createAppendableJournalStore({ runFilePath: runFilePath.value, fs: fs8 });
8122
+ try {
8123
+ return { ok: true, value: await store.isSealed() };
8124
+ } catch (error) {
8125
+ return { ok: false, error: `${JOURNAL_RUNTIME_ERROR.READ_FAILED}: ${toMessage(error)}` };
8126
+ }
8127
+ }
8007
8128
  async function renderJournalRun(ref, projection, options = {}) {
8008
8129
  const bound = await bindJournal(ref, options.fs);
8009
8130
  if (!bound.ok) return bound;
@@ -11479,6 +11600,20 @@ function aggregateTestExitCode(invocations, unsupportedSelectionCount = 0) {
11479
11600
  return SUCCESS_EXIT_CODE;
11480
11601
  }
11481
11602
 
11603
+ // src/config/source-roots.ts
11604
+ var TEST_RELEVANT_SOURCE_ROOT_PREFIX = {
11605
+ SOURCE: "src/",
11606
+ TESTING: "testing/",
11607
+ SCRIPTS: "scripts/",
11608
+ ESLINT_RULES: "eslint-rules/"
11609
+ };
11610
+ var TEST_RELEVANT_SOURCE_ROOT_PREFIXES = [
11611
+ TEST_RELEVANT_SOURCE_ROOT_PREFIX.SOURCE,
11612
+ TEST_RELEVANT_SOURCE_ROOT_PREFIX.TESTING,
11613
+ TEST_RELEVANT_SOURCE_ROOT_PREFIX.SCRIPTS,
11614
+ TEST_RELEVANT_SOURCE_ROOT_PREFIX.ESLINT_RULES
11615
+ ];
11616
+
11482
11617
  // src/domains/test/changed-set-planning.ts
11483
11618
  var PATH_SEPARATOR = "/";
11484
11619
  var MARKDOWN_EXTENSION = ".md";
@@ -11683,8 +11818,8 @@ var PRODUCT_INPUT_DIGEST_FIELDS = {
11683
11818
  DESCRIPTOR_ID: "descriptorId",
11684
11819
  DIGEST: "digest"
11685
11820
  };
11686
- var SHA256_ALGORITHM3 = "sha256";
11687
- var HEX_ENCODING3 = "hex";
11821
+ var SHA256_ALGORITHM2 = "sha256";
11822
+ var HEX_ENCODING2 = "hex";
11688
11823
  var SEGMENT_SEPARATOR = "-";
11689
11824
  var defaultFileSystem2 = defaultFileSystem;
11690
11825
  function formatTestRunTimestamp(date) {
@@ -11960,7 +12095,7 @@ function isRecord6(value) {
11960
12095
  return typeof value === "object" && value !== null && !Array.isArray(value);
11961
12096
  }
11962
12097
  function sha256Hex2(value) {
11963
- return createHash4(SHA256_ALGORITHM3).update(value).digest(HEX_ENCODING3);
12098
+ return createHash4(SHA256_ALGORITHM2).update(value).digest(HEX_ENCODING2);
11964
12099
  }
11965
12100
  var UNKNOWN_ERROR_MESSAGE = "unknown error";
11966
12101
  function toErrorMessage3(error) {
@@ -19418,13 +19553,13 @@ async function persistVerificationContext(scope2, document, options = {}) {
19418
19553
  const existing = await readExistingContext(fs8, contextPath.value);
19419
19554
  if (!existing.ok) return existing;
19420
19555
  if (existing.value === document.canonicalJson) {
19421
- return { ok: true, value: { digest: document.digest, contextPath: contextPath.value } };
19556
+ return { ok: true, value: { digest: document.digest, contextPath: contextPath.value, created: false } };
19422
19557
  }
19423
19558
  return { ok: false, error: VERIFICATION_CONTEXT_RUNTIME_ERROR.CONTENT_MISMATCH };
19424
19559
  }
19425
19560
  return { ok: false, error: `${VERIFICATION_CONTEXT_RUNTIME_ERROR.WRITE_FAILED}: ${toMessage(error)}` };
19426
19561
  }
19427
- return { ok: true, value: { digest: document.digest, contextPath: contextPath.value } };
19562
+ return { ok: true, value: { digest: document.digest, contextPath: contextPath.value, created: true } };
19428
19563
  }
19429
19564
  async function readExistingContext(fs8, contextPath) {
19430
19565
  try {
@@ -19570,6 +19705,7 @@ var verificationContextDomain = {
19570
19705
  import { readFile as readFile13 } from "fs/promises";
19571
19706
 
19572
19707
  // src/commands/verify/cli.ts
19708
+ import { randomBytes as randomBytes2 } from "crypto";
19573
19709
  import { dirname as dirname12 } from "path";
19574
19710
 
19575
19711
  // src/domains/verify/verify.ts
@@ -19582,18 +19718,93 @@ var VERIFY_VERB = {
19582
19718
  START: "start",
19583
19719
  INPUT: "input",
19584
19720
  APPEND_SCOPE: "append-scope",
19585
- APPEND_FINDING: "append-finding"
19721
+ APPEND_FINDING: "append-finding",
19722
+ FINISH: "finish",
19723
+ STATUS: "status",
19724
+ RENDER: "render"
19586
19725
  };
19726
+ var VERIFY_LIFECYCLE_ACTION = {
19727
+ SCOPE_ADD: "scope add",
19728
+ FINDING_ADD: "finding add",
19729
+ FINISH: VERIFY_VERB.FINISH
19730
+ };
19731
+ var UNSEALED_NEXT_ACTIONS = [
19732
+ VERIFY_LIFECYCLE_ACTION.SCOPE_ADD,
19733
+ VERIFY_LIFECYCLE_ACTION.FINDING_ADD,
19734
+ VERIFY_LIFECYCLE_ACTION.FINISH
19735
+ ];
19587
19736
  var VERIFY_VERIFICATION_TYPE = {
19737
+ AUDIT: "audit",
19588
19738
  REVIEW: "review"
19589
19739
  };
19740
+ var VERIFY_VERIFICATION_TYPES = new Set(Object.values(VERIFY_VERIFICATION_TYPE));
19741
+ function isVerifyVerificationType(value) {
19742
+ return VERIFY_VERIFICATION_TYPES.has(value);
19743
+ }
19590
19744
  var REVIEW_FINDING_DISPOSITION = {
19591
19745
  BLOCKING: "BLOCKING",
19592
19746
  DEBT: "DEBT"
19593
19747
  };
19748
+ var REVIEW_SCOPE_COVERAGE_STATE = {
19749
+ CLEAN: "clean",
19750
+ FINDING: "finding"
19751
+ };
19752
+ var REVIEW_ANCHOR_SIDE = {
19753
+ LEFT: "LEFT",
19754
+ RIGHT: "RIGHT"
19755
+ };
19756
+ var REVIEW_TERMINAL_STATE = {
19757
+ APPROVED: "approved",
19758
+ CHANGES_REQUESTED: "changes_requested",
19759
+ COMMENTED: "commented"
19760
+ };
19761
+ var AUDIT_CLASS = {
19762
+ IMPLEMENTATION: "implementation",
19763
+ INSTRUCTIONS: "instructions",
19764
+ SPEC: "spec"
19765
+ };
19766
+ var AUDIT_KIND = {
19767
+ ADR: "adr",
19768
+ ARCHITECTURE: "architecture",
19769
+ CODE: "code",
19770
+ COVERAGE_GAP: "coverage-gap",
19771
+ EVAL_EVIDENCE: "eval-evidence",
19772
+ GUIDE_TEMPLATE: "guide-template",
19773
+ PDR: "pdr",
19774
+ PROMPT: "prompt",
19775
+ SKILL: "skill",
19776
+ SPEC: "spec",
19777
+ SUBAGENT: "subagent",
19778
+ TESTS: "tests"
19779
+ };
19780
+ var AUDIT_COVERAGE_REQUIREMENT = {
19781
+ OPTIONAL: "optional",
19782
+ REQUIRED: "required"
19783
+ };
19784
+ var AUDIT_COVERAGE_STATUS = {
19785
+ AUDITED: "audited",
19786
+ INCOMPLETE: "incomplete",
19787
+ MISSING_SKILL: "missing-skill",
19788
+ NOT_APPLICABLE: "not-applicable",
19789
+ SKIPPED: "skipped",
19790
+ UNSUPPORTED: "unsupported"
19791
+ };
19792
+ var AUDIT_FINDING_SEVERITY = {
19793
+ BLOCKING: "blocking",
19794
+ DEBT: "debt"
19795
+ };
19796
+ var TERMINAL_METADATA_VALIDATION_ERROR = {
19797
+ METADATA_INVALID: "metadata-invalid",
19798
+ STATUS_CONFLICT: "status-conflict"
19799
+ };
19800
+ var VERIFY_EVIDENCE_KIND = {
19801
+ SCOPE: "scope",
19802
+ FINDING: "finding",
19803
+ TERMINAL_METADATA: "terminal-metadata"
19804
+ };
19594
19805
  var VERIFY_APPEND_EVENT_TYPE = {
19595
- SCOPE: "io.spx.verify.scope",
19596
- FINDING: "io.spx.verify.finding"
19806
+ SCOPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.scope`,
19807
+ FINDING: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.finding`
19597
19808
  };
19598
19809
  var VERIFY_EVENT_SOURCE = "/spx/verify";
19599
19810
  var VERIFY_APPEND_EVENT_FIELD = {
@@ -19611,7 +19822,9 @@ var VERIFY_SCOPE_ERROR = {
19611
19822
  var VERIFY_INPUT_DIGEST_PATH = "verify run input";
19612
19823
  function parseChangesetScope(scope2) {
19613
19824
  const separatorIndex = scope2.indexOf(VERIFY_SCOPE_SEPARATOR);
19614
- if (separatorIndex < 0) return { ok: false, error: VERIFY_SCOPE_ERROR.MALFORMED_CHANGESET };
19825
+ if (separatorIndex < 0) {
19826
+ return { ok: false, error: VERIFY_SCOPE_ERROR.MALFORMED_CHANGESET };
19827
+ }
19615
19828
  const base = scope2.slice(0, separatorIndex);
19616
19829
  const head = scope2.slice(separatorIndex + VERIFY_SCOPE_SEPARATOR.length);
19617
19830
  if (base.length === 0 || head.length === 0 || head.includes(VERIFY_SCOPE_SEPARATOR)) {
@@ -19631,7 +19844,10 @@ function buildRunLocator(parts) {
19631
19844
  };
19632
19845
  }
19633
19846
  function digestRunInput(source, content) {
19634
- const digest = digestDescriptorSection({ source, content }, VERIFY_INPUT_DIGEST_PATH);
19847
+ const digest = digestDescriptorSection(
19848
+ { source, content },
19849
+ VERIFY_INPUT_DIGEST_PATH
19850
+ );
19635
19851
  if (!digest.ok) return digest;
19636
19852
  return { ok: true, value: digest.value.sha256 };
19637
19853
  }
@@ -19651,7 +19867,10 @@ function verifyInputRecordPath(scope2) {
19651
19867
  if (!token.ok) return token;
19652
19868
  return {
19653
19869
  ok: true,
19654
- value: join36(runs.value, `${VERIFY_INPUT_RECORD.PREFIX}${token.value}${VERIFY_INPUT_RECORD.SUFFIX}`)
19870
+ value: join36(
19871
+ runs.value,
19872
+ `${VERIFY_INPUT_RECORD.PREFIX}${token.value}${VERIFY_INPUT_RECORD.SUFFIX}`
19873
+ )
19655
19874
  };
19656
19875
  }
19657
19876
  var VERIFY_APPEND_ATTEMPT = 1;
@@ -19665,67 +19884,546 @@ function parseAppendPayload(raw) {
19665
19884
  function isJsonRecord(value) {
19666
19885
  return typeof value === "object" && value !== null && !Array.isArray(value);
19667
19886
  }
19887
+ function readRequiredString(record6, field) {
19888
+ const value = record6[field];
19889
+ return typeof value === "string" && value.length > 0 ? value : void 0;
19890
+ }
19891
+ function readRequiredStringValue(record6, field) {
19892
+ const value = record6[field];
19893
+ return typeof value === "string" ? value : void 0;
19894
+ }
19895
+ var OPTIONAL_FIELD_STATE = {
19896
+ ABSENT: "absent",
19897
+ INVALID: "invalid",
19898
+ PRESENT: "present"
19899
+ };
19900
+ function readOptionalString2(record6, field) {
19901
+ if (!(field in record6)) return { state: OPTIONAL_FIELD_STATE.ABSENT };
19902
+ const value = record6[field];
19903
+ return typeof value === "string" && value.length > 0 ? { state: OPTIONAL_FIELD_STATE.PRESENT, value } : { state: OPTIONAL_FIELD_STATE.INVALID };
19904
+ }
19905
+ function readOptionalPositiveInteger(record6, field) {
19906
+ if (!(field in record6)) return { state: OPTIONAL_FIELD_STATE.ABSENT };
19907
+ const value = record6[field];
19908
+ return typeof value === "number" && Number.isInteger(value) && value > 0 ? { state: OPTIONAL_FIELD_STATE.PRESENT, value } : { state: OPTIONAL_FIELD_STATE.INVALID };
19909
+ }
19910
+ function optionalFieldValue(field) {
19911
+ return field.state === OPTIONAL_FIELD_STATE.PRESENT ? field.value : void 0;
19912
+ }
19913
+ function readRequiredRecord(record6, field) {
19914
+ const value = record6[field];
19915
+ return isJsonRecord(value) ? value : void 0;
19916
+ }
19917
+ function readOptionalRecord(record6, field) {
19918
+ if (!(field in record6)) return { state: OPTIONAL_FIELD_STATE.ABSENT };
19919
+ const value = record6[field];
19920
+ return isJsonRecord(value) ? { state: OPTIONAL_FIELD_STATE.PRESENT, value } : { state: OPTIONAL_FIELD_STATE.INVALID };
19921
+ }
19922
+ function hasInvalidOptionalField(...fields) {
19923
+ return fields.some((field) => field.state === OPTIONAL_FIELD_STATE.INVALID);
19924
+ }
19668
19925
  function isReviewFindingDisposition(value) {
19669
19926
  return Object.values(REVIEW_FINDING_DISPOSITION).includes(value);
19670
19927
  }
19671
- function validateReviewFinding(payload) {
19928
+ function isReviewScopeCoverageState(value) {
19929
+ return typeof value === "string" && Object.values(REVIEW_SCOPE_COVERAGE_STATE).includes(value);
19930
+ }
19931
+ function isReviewAnchorSide(value) {
19932
+ return typeof value === "string" && Object.values(REVIEW_ANCHOR_SIDE).includes(value);
19933
+ }
19934
+ function isReviewTerminalState(value) {
19935
+ return typeof value === "string" && Object.values(REVIEW_TERMINAL_STATE).includes(value);
19936
+ }
19937
+ function isAuditClass(value) {
19938
+ return typeof value === "string" && Object.values(AUDIT_CLASS).includes(value);
19939
+ }
19940
+ function isAuditKind(value) {
19941
+ return typeof value === "string" && Object.values(AUDIT_KIND).includes(value);
19942
+ }
19943
+ function isAuditCoverageRequirement(value) {
19944
+ return typeof value === "string" && Object.values(AUDIT_COVERAGE_REQUIREMENT).includes(value);
19945
+ }
19946
+ function isAuditCoverageStatus(value) {
19947
+ return typeof value === "string" && Object.values(AUDIT_COVERAGE_STATUS).includes(value);
19948
+ }
19949
+ function isAuditFindingSeverity(value) {
19950
+ return typeof value === "string" && Object.values(AUDIT_FINDING_SEVERITY).includes(value);
19951
+ }
19952
+ function isCompatibleAuditKind(auditClass, auditKind) {
19953
+ if (auditKind === AUDIT_KIND.COVERAGE_GAP) return true;
19954
+ if (auditClass === AUDIT_CLASS.INSTRUCTIONS) {
19955
+ return auditKind === AUDIT_KIND.SKILL || auditKind === AUDIT_KIND.SUBAGENT || auditKind === AUDIT_KIND.PROMPT || auditKind === AUDIT_KIND.GUIDE_TEMPLATE;
19956
+ }
19957
+ if (auditClass === AUDIT_CLASS.SPEC) {
19958
+ return auditKind === AUDIT_KIND.SPEC || auditKind === AUDIT_KIND.ADR || auditKind === AUDIT_KIND.PDR;
19959
+ }
19960
+ return auditKind === AUDIT_KIND.CODE || auditKind === AUDIT_KIND.TESTS || auditKind === AUDIT_KIND.ARCHITECTURE || auditKind === AUDIT_KIND.EVAL_EVIDENCE;
19961
+ }
19962
+ function evidencePayloadValidator(validator) {
19963
+ return (input) => validator(input.payload);
19964
+ }
19965
+ function readReviewFindingMetadata(payload) {
19672
19966
  if (!isJsonRecord(payload)) return void 0;
19673
19967
  const { disposition, summary } = payload;
19674
19968
  if (!isReviewFindingDisposition(disposition)) return void 0;
19675
19969
  if (typeof summary !== "string" || summary.length === 0) return void 0;
19676
19970
  return { disposition, summary };
19677
19971
  }
19678
- var FINDING_VALIDATORS = {
19679
- [VERIFY_VERIFICATION_TYPE.REVIEW]: validateReviewFinding
19680
- };
19681
- function findingValidatorFor(verificationType) {
19682
- return FINDING_VALIDATORS[verificationType];
19972
+ function validateReviewFinding(payload) {
19973
+ if (!isJsonRecord(payload)) return void 0;
19974
+ const path7 = readRequiredString(payload, "path");
19975
+ const originalCommit = readRequiredString(payload, "originalCommit");
19976
+ const diffHunk = readRequiredString(payload, "diffHunk");
19977
+ const body = readRequiredString(payload, "body");
19978
+ const { side } = payload;
19979
+ const finding = readReviewFindingMetadata(payload.finding);
19980
+ if (path7 === void 0 || originalCommit === void 0 || diffHunk === void 0 || body === void 0) {
19981
+ return void 0;
19982
+ }
19983
+ if (!isReviewAnchorSide(side)) return void 0;
19984
+ if (finding === void 0) return void 0;
19985
+ const line = readOptionalPositiveInteger(payload, "line");
19986
+ const position = readOptionalPositiveInteger(payload, "position");
19987
+ const providerIdentity = readOptionalString2(payload, "providerIdentity");
19988
+ const url = readOptionalString2(payload, "url");
19989
+ if (hasInvalidOptionalField(line, position, providerIdentity, url)) return void 0;
19990
+ const lineValue = optionalFieldValue(line);
19991
+ const positionValue = optionalFieldValue(position);
19992
+ if (lineValue === void 0 && positionValue === void 0) return void 0;
19993
+ const providerIdentityValue = optionalFieldValue(providerIdentity);
19994
+ const urlValue = optionalFieldValue(url);
19995
+ return {
19996
+ path: path7,
19997
+ side,
19998
+ originalCommit,
19999
+ diffHunk,
20000
+ body,
20001
+ finding,
20002
+ ...providerIdentityValue === void 0 ? {} : { providerIdentity: providerIdentityValue },
20003
+ ...lineValue === void 0 ? {} : { line: lineValue },
20004
+ ...positionValue === void 0 ? {} : { position: positionValue },
20005
+ ...urlValue === void 0 ? {} : { url: urlValue }
20006
+ };
19683
20007
  }
19684
- function findAppendedSequence(events, idempotencyKey, eventType) {
19685
- const match = events.find(
19686
- (event) => event.type === eventType && isJsonRecord(event.data) && event.data[VERIFY_APPEND_EVENT_FIELD.IDEMPOTENCY_KEY] === idempotencyKey
19687
- );
19688
- return match?.seq;
20008
+ function validateReviewScope(payload) {
20009
+ if (!isJsonRecord(payload)) return void 0;
20010
+ const path7 = readRequiredString(payload, "path");
20011
+ const commit = readRequiredString(payload, "commit");
20012
+ const { side, coverageState } = payload;
20013
+ if (path7 === void 0 || commit === void 0) return void 0;
20014
+ if (!isReviewAnchorSide(side)) return void 0;
20015
+ if (!isReviewScopeCoverageState(coverageState)) return void 0;
20016
+ const line = readOptionalPositiveInteger(payload, "line");
20017
+ const position = readOptionalPositiveInteger(payload, "position");
20018
+ const providerIdentity = readOptionalString2(payload, "providerIdentity");
20019
+ const url = readOptionalString2(payload, "url");
20020
+ if (hasInvalidOptionalField(line, position, providerIdentity, url)) return void 0;
20021
+ const lineValue = optionalFieldValue(line);
20022
+ const positionValue = optionalFieldValue(position);
20023
+ const providerIdentityValue = optionalFieldValue(providerIdentity);
20024
+ const urlValue = optionalFieldValue(url);
20025
+ return {
20026
+ path: path7,
20027
+ side,
20028
+ commit,
20029
+ coverageState,
20030
+ ...providerIdentityValue === void 0 ? {} : { providerIdentity: providerIdentityValue },
20031
+ ...lineValue === void 0 ? {} : { line: lineValue },
20032
+ ...positionValue === void 0 ? {} : { position: positionValue },
20033
+ ...urlValue === void 0 ? {} : { url: urlValue }
20034
+ };
19689
20035
  }
19690
- function buildAppendEvent(args) {
20036
+ function validateReviewTerminalMetadata(payload) {
20037
+ if (!isJsonRecord(payload)) return void 0;
20038
+ const actor = readRequiredString(payload, "actor");
20039
+ const body = readRequiredStringValue(payload, "body");
20040
+ const submittedAt = readRequiredString(payload, "submittedAt");
20041
+ const commit = readRequiredString(payload, "commit");
20042
+ const { state } = payload;
20043
+ if (actor === void 0 || body === void 0 || submittedAt === void 0 || commit === void 0) return void 0;
20044
+ if (!isReviewTerminalState(state)) return void 0;
20045
+ const providerIdentity = readOptionalString2(payload, "providerIdentity");
20046
+ const url = readOptionalString2(payload, "url");
20047
+ if (hasInvalidOptionalField(providerIdentity, url)) return void 0;
20048
+ const providerIdentityValue = optionalFieldValue(providerIdentity);
20049
+ const urlValue = optionalFieldValue(url);
19691
20050
  return {
19692
- id: args.idempotencyKey,
19693
- source: VERIFY_EVENT_SOURCE,
19694
- type: args.eventType,
19695
- time: args.at.toISOString(),
19696
- attempt: VERIFY_APPEND_ATTEMPT,
19697
- data: {
19698
- [VERIFY_APPEND_EVENT_FIELD.IDEMPOTENCY_KEY]: args.idempotencyKey,
19699
- [VERIFY_APPEND_EVENT_FIELD.PAYLOAD]: args.payload
20051
+ actor,
20052
+ state,
20053
+ body,
20054
+ submittedAt,
20055
+ commit,
20056
+ ...providerIdentityValue === void 0 ? {} : { providerIdentity: providerIdentityValue },
20057
+ ...urlValue === void 0 ? {} : { url: urlValue }
20058
+ };
20059
+ }
20060
+ function validateReviewTerminal(input) {
20061
+ const validated = input.metadata === void 0 ? void 0 : validateReviewTerminalMetadata(input.metadata);
20062
+ if (input.metadata !== void 0 && validated === void 0) {
20063
+ return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.METADATA_INVALID };
20064
+ }
20065
+ const evidenceStatus = expectedReviewEvidenceTerminalStatus(input.events);
20066
+ const metadataStatus = expectedReviewMetadataTerminalStatus(validated);
20067
+ if (evidenceStatus !== void 0 && metadataStatus !== void 0 && evidenceStatus !== metadataStatus) {
20068
+ return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.STATUS_CONFLICT };
20069
+ }
20070
+ const expectedStatus = evidenceStatus ?? metadataStatus;
20071
+ if (expectedStatus !== void 0 && input.terminalStatus !== expectedStatus) {
20072
+ return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.STATUS_CONFLICT };
20073
+ }
20074
+ if (validated === void 0) return { ok: true, value: void 0 };
20075
+ return {
20076
+ ok: true,
20077
+ value: {
20078
+ actor: validated.actor,
20079
+ state: validated.state,
20080
+ body: validated.body,
20081
+ submittedAt: validated.submittedAt,
20082
+ commit: validated.commit,
20083
+ ...validated.providerIdentity === void 0 ? {} : { providerIdentity: validated.providerIdentity },
20084
+ ...validated.url === void 0 ? {} : { url: validated.url }
19700
20085
  }
19701
20086
  };
19702
20087
  }
19703
-
19704
- // src/commands/verify/cli.ts
19705
- var VERIFY_CLI_EXIT_CODE = {
19706
- OK: 0,
19707
- ERROR: 1
19708
- };
19709
- var VERIFY_CLI_ENV = {
19710
- BRANCH: SPX_VERIFY_ENV.BRANCH
19711
- };
19712
- var VERIFY_CLI_ERROR = {
19713
- INPUT_REQUIRED: "spx verify start requires --input <input-source>",
19714
- RUN_REQUIRED: "spx verify existing-run verbs require an explicit --run <run-token>",
19715
- RUN_NOT_FOUND: "spx verify could not locate the requested run",
19716
- CHANGED_SCOPE_FAILED: "spx verify could not derive the changeset changed-file scope",
19717
- INPUT_PERSIST_FAILED: "spx verify could not persist the recorded run input",
19718
- INPUT_READ_FAILED: "spx verify could not read the recorded run input",
19719
- PAYLOAD_REQUIRED: "spx verify append verbs require --payload <payload-source>",
19720
- IDEMPOTENCY_KEY_REQUIRED: "spx verify append verbs require --idempotency-key <key>",
19721
- PAYLOAD_READ_FAILED: "spx verify could not read the append payload",
19722
- PAYLOAD_INVALID: "spx verify append payload is not valid JSON",
19723
- FINDING_INVALID: "spx verify append-finding payload failed verification-type validation",
19724
- UNSUPPORTED_VERIFICATION_TYPE: "spx verify append-finding has no finding validator for the verification type",
19725
- APPEND_FAILED: "spx verify could not append the evidence event"
19726
- };
19727
- function okResult3(output) {
19728
- return { exitCode: VERIFY_CLI_EXIT_CODE.OK, output };
20088
+ function validateAuditProducerIdentity(payload) {
20089
+ if (!isJsonRecord(payload)) return void 0;
20090
+ const producerKind = readRequiredString(payload, "producerKind");
20091
+ const agentName = readRequiredString(payload, "agentName");
20092
+ const agentOwningPluginName = readRequiredString(payload, "agentOwningPluginName");
20093
+ const skillName = readRequiredString(payload, "skillName");
20094
+ const skillOwningPluginName = readRequiredString(payload, "skillOwningPluginName");
20095
+ const invocationRole = readRequiredString(payload, "invocationRole");
20096
+ if (producerKind === void 0 || agentName === void 0 || agentOwningPluginName === void 0 || skillName === void 0 || skillOwningPluginName === void 0 || invocationRole === void 0) {
20097
+ return void 0;
20098
+ }
20099
+ return {
20100
+ producerKind,
20101
+ agentName,
20102
+ agentOwningPluginName,
20103
+ skillName,
20104
+ skillOwningPluginName,
20105
+ invocationRole
20106
+ };
20107
+ }
20108
+ function validateAuditProducerProvenance(payload) {
20109
+ if (!isJsonRecord(payload)) return void 0;
20110
+ const agentOwningPluginVersion = readRequiredString(payload, "agentOwningPluginVersion");
20111
+ const skillOwningPluginVersion = readRequiredString(payload, "skillOwningPluginVersion");
20112
+ if (agentOwningPluginVersion === void 0 || skillOwningPluginVersion === void 0) return void 0;
20113
+ const toolVersion = readOptionalString2(payload, "toolVersion");
20114
+ if (hasInvalidOptionalField(toolVersion)) return void 0;
20115
+ const toolVersionValue = optionalFieldValue(toolVersion);
20116
+ return {
20117
+ agentOwningPluginVersion,
20118
+ skillOwningPluginVersion,
20119
+ ...toolVersionValue === void 0 ? {} : { toolVersion: toolVersionValue }
20120
+ };
20121
+ }
20122
+ function validateAuditPriorContextPartitions(payload) {
20123
+ if (!isJsonRecord(payload)) return void 0;
20124
+ const changedFilePartition = readRequiredString(payload, "changedFilePartition");
20125
+ const concernPartition = readRequiredString(payload, "concernPartition");
20126
+ if (changedFilePartition === void 0 || concernPartition === void 0) return void 0;
20127
+ const languagePartition = readOptionalString2(payload, "languagePartition");
20128
+ if (hasInvalidOptionalField(languagePartition)) return void 0;
20129
+ const languagePartitionValue = optionalFieldValue(languagePartition);
20130
+ return {
20131
+ changedFilePartition,
20132
+ concernPartition,
20133
+ ...languagePartitionValue === void 0 ? {} : { languagePartition: languagePartitionValue }
20134
+ };
20135
+ }
20136
+ function validateOptionalAuditProducerProvenance(producerProvenance) {
20137
+ if (producerProvenance.state !== OPTIONAL_FIELD_STATE.PRESENT) return producerProvenance;
20138
+ const value = validateAuditProducerProvenance(producerProvenance.value);
20139
+ return value === void 0 ? { state: OPTIONAL_FIELD_STATE.INVALID } : { state: OPTIONAL_FIELD_STATE.PRESENT, value };
20140
+ }
20141
+ function auditKindAllowsProducerProvenance(auditKind, producerProvenance) {
20142
+ return auditKind !== AUDIT_KIND.COVERAGE_GAP || producerProvenance === void 0;
20143
+ }
20144
+ function auditKindAllowsCoverageStatus(auditKind, coverageStatus) {
20145
+ return auditKind !== AUDIT_KIND.COVERAGE_GAP || coverageStatus !== AUDIT_COVERAGE_STATUS.AUDITED && coverageStatus !== AUDIT_COVERAGE_STATUS.NOT_APPLICABLE;
20146
+ }
20147
+ function validateAuditScope(payload) {
20148
+ if (!isJsonRecord(payload)) return void 0;
20149
+ const unitId = readRequiredString(payload, "unitId");
20150
+ const subject = readRequiredString(payload, "subject");
20151
+ const { auditClass, auditKind, coverageRequirement, coverageStatus } = payload;
20152
+ if (unitId === void 0 || subject === void 0) return void 0;
20153
+ if (!isAuditClass(auditClass) || !isAuditKind(auditKind)) return void 0;
20154
+ if (!isCompatibleAuditKind(auditClass, auditKind)) return void 0;
20155
+ if (!isAuditCoverageRequirement(coverageRequirement)) return void 0;
20156
+ if (!isAuditCoverageStatus(coverageStatus)) return void 0;
20157
+ if (!auditKindAllowsCoverageStatus(auditKind, coverageStatus)) return void 0;
20158
+ const priorContext = validateAuditPriorContextPartitions(readRequiredRecord(payload, "priorContext"));
20159
+ const expectedProducer = validateAuditProducerIdentity(readRequiredRecord(payload, "expectedProducer"));
20160
+ const recordedByRunDriver = validateAuditProducerIdentity(readRequiredRecord(payload, "recordedByRunDriver"));
20161
+ if (priorContext === void 0 || expectedProducer === void 0 || recordedByRunDriver === void 0) {
20162
+ return void 0;
20163
+ }
20164
+ const parentUnitId = readOptionalString2(payload, "parentUnitId");
20165
+ const producerProvenance = validateOptionalAuditProducerProvenance(
20166
+ readOptionalRecord(payload, "producerProvenance")
20167
+ );
20168
+ if (hasInvalidOptionalField(parentUnitId, producerProvenance)) return void 0;
20169
+ const parentUnitIdValue = optionalFieldValue(parentUnitId);
20170
+ const producerProvenanceValue = optionalFieldValue(producerProvenance);
20171
+ if (parentUnitIdValue === unitId) return void 0;
20172
+ if (!auditKindAllowsProducerProvenance(auditKind, producerProvenanceValue)) return void 0;
20173
+ return {
20174
+ unitId,
20175
+ auditClass,
20176
+ auditKind,
20177
+ subject,
20178
+ coverageRequirement,
20179
+ coverageStatus,
20180
+ priorContext,
20181
+ expectedProducer,
20182
+ recordedByRunDriver,
20183
+ ...parentUnitIdValue === void 0 ? {} : { parentUnitId: parentUnitIdValue },
20184
+ ...producerProvenanceValue === void 0 ? {} : { producerProvenance: producerProvenanceValue }
20185
+ };
20186
+ }
20187
+ function validateAuditFindingEvidence(evidence) {
20188
+ if (evidence === void 0) return void 0;
20189
+ const observed = readRequiredString(evidence, "observed");
20190
+ const expected = readRequiredString(evidence, "expected");
20191
+ if (observed === void 0 || expected === void 0) return void 0;
20192
+ return { observed, expected };
20193
+ }
20194
+ function validateAuditFinding(payload) {
20195
+ if (!isJsonRecord(payload)) return void 0;
20196
+ const unitId = readRequiredString(payload, "unitId");
20197
+ const rule = readRequiredString(payload, "rule");
20198
+ const location = readRequiredString(payload, "location");
20199
+ const message = readRequiredString(payload, "message");
20200
+ const { severity } = payload;
20201
+ if (unitId === void 0 || rule === void 0 || location === void 0 || message === void 0) {
20202
+ return void 0;
20203
+ }
20204
+ if (!isAuditFindingSeverity(severity)) return void 0;
20205
+ const producerIdentity = validateAuditProducerIdentity(readRequiredRecord(payload, "producerIdentity"));
20206
+ const producerProvenance = validateAuditProducerProvenance(readRequiredRecord(payload, "producerProvenance"));
20207
+ const evidence = validateAuditFindingEvidence(readRequiredRecord(payload, "evidence"));
20208
+ if (producerIdentity === void 0 || producerProvenance === void 0 || evidence === void 0) {
20209
+ return void 0;
20210
+ }
20211
+ return {
20212
+ unitId,
20213
+ producerIdentity,
20214
+ producerProvenance,
20215
+ rule,
20216
+ severity,
20217
+ location,
20218
+ message,
20219
+ evidence
20220
+ };
20221
+ }
20222
+ function auditFindingReferencesRecordedScope(events, finding) {
20223
+ return events.some((event) => {
20224
+ if (event.type !== VERIFY_APPEND_EVENT_TYPE.SCOPE || !isJsonRecord(event.data)) return false;
20225
+ const scope2 = validateAuditScope(event.data[VERIFY_APPEND_EVENT_FIELD.PAYLOAD]);
20226
+ return scope2?.unitId === finding.unitId;
20227
+ });
20228
+ }
20229
+ function validateAuditFindingForRun(input) {
20230
+ const finding = validateAuditFinding(input.payload);
20231
+ if (finding === void 0) return void 0;
20232
+ return auditFindingReferencesRecordedScope(input.events, finding) ? finding : void 0;
20233
+ }
20234
+ var EVIDENCE_VALIDATORS = {
20235
+ [VERIFY_VERIFICATION_TYPE.AUDIT]: {
20236
+ [VERIFY_EVIDENCE_KIND.SCOPE]: evidencePayloadValidator(validateAuditScope),
20237
+ [VERIFY_EVIDENCE_KIND.FINDING]: validateAuditFindingForRun,
20238
+ [VERIFY_EVIDENCE_KIND.TERMINAL_METADATA]: validateAuditTerminal
20239
+ },
20240
+ [VERIFY_VERIFICATION_TYPE.REVIEW]: {
20241
+ [VERIFY_EVIDENCE_KIND.SCOPE]: evidencePayloadValidator(validateReviewScope),
20242
+ [VERIFY_EVIDENCE_KIND.FINDING]: evidencePayloadValidator(validateReviewFinding),
20243
+ [VERIFY_EVIDENCE_KIND.TERMINAL_METADATA]: validateReviewTerminal
20244
+ }
20245
+ };
20246
+ function evidenceValidatorFor(verificationType, evidenceKind) {
20247
+ return EVIDENCE_VALIDATORS[verificationType]?.[evidenceKind];
20248
+ }
20249
+ function terminalMetadataValidatorFor(verificationType) {
20250
+ return EVIDENCE_VALIDATORS[verificationType]?.[VERIFY_EVIDENCE_KIND.TERMINAL_METADATA];
20251
+ }
20252
+ function expectedReviewEvidenceTerminalStatus(events) {
20253
+ if (countVerifyFindings(events) > 0 || countReviewScopeFindingUnits(events) > 0) {
20254
+ return JOURNAL_RUN_STATE_STATUS.REJECTED;
20255
+ }
20256
+ return void 0;
20257
+ }
20258
+ function auditCoverageRejectsRun(scope2) {
20259
+ if (scope2.coverageRequirement !== AUDIT_COVERAGE_REQUIREMENT.REQUIRED) return false;
20260
+ return scope2.auditKind === AUDIT_KIND.COVERAGE_GAP || scope2.coverageStatus === AUDIT_COVERAGE_STATUS.UNSUPPORTED || scope2.coverageStatus === AUDIT_COVERAGE_STATUS.MISSING_SKILL || scope2.coverageStatus === AUDIT_COVERAGE_STATUS.SKIPPED || scope2.coverageStatus === AUDIT_COVERAGE_STATUS.INCOMPLETE;
20261
+ }
20262
+ function expectedAuditTerminalStatus(events) {
20263
+ const hasFinding = countVerifyFindings(events) > 0;
20264
+ const auditScopeEvents = events.filter((event) => {
20265
+ if (event.type !== VERIFY_APPEND_EVENT_TYPE.SCOPE || !isJsonRecord(event.data)) return false;
20266
+ return validateAuditScope(event.data[VERIFY_APPEND_EVENT_FIELD.PAYLOAD]) !== void 0;
20267
+ });
20268
+ const hasUncoveredRequiredScope = events.some((event) => {
20269
+ if (event.type !== VERIFY_APPEND_EVENT_TYPE.SCOPE || !isJsonRecord(event.data)) return false;
20270
+ const payload = event.data[VERIFY_APPEND_EVENT_FIELD.PAYLOAD];
20271
+ const scope2 = validateAuditScope(payload);
20272
+ return scope2 === void 0 ? false : auditCoverageRejectsRun(scope2);
20273
+ });
20274
+ return hasFinding || auditScopeEvents.length === 0 || hasUncoveredRequiredScope ? JOURNAL_RUN_STATE_STATUS.REJECTED : JOURNAL_RUN_STATE_STATUS.APPROVED;
20275
+ }
20276
+ function validateAuditTerminal(input) {
20277
+ if (input.metadata !== void 0) {
20278
+ return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.METADATA_INVALID };
20279
+ }
20280
+ if (input.terminalStatus !== expectedAuditTerminalStatus(input.events)) {
20281
+ return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.STATUS_CONFLICT };
20282
+ }
20283
+ return { ok: true, value: void 0 };
20284
+ }
20285
+ function expectedReviewMetadataTerminalStatus(metadata) {
20286
+ if (metadata?.state === REVIEW_TERMINAL_STATE.APPROVED) return JOURNAL_RUN_STATE_STATUS.APPROVED;
20287
+ if (metadata?.state === REVIEW_TERMINAL_STATE.CHANGES_REQUESTED) return JOURNAL_RUN_STATE_STATUS.REJECTED;
20288
+ return void 0;
20289
+ }
20290
+ function findAppendedSequence(events, idempotencyKey, eventType) {
20291
+ const match = events.find(
20292
+ (event) => event.type === eventType && isJsonRecord(event.data) && event.data[VERIFY_APPEND_EVENT_FIELD.IDEMPOTENCY_KEY] === idempotencyKey
20293
+ );
20294
+ return match?.seq;
20295
+ }
20296
+ function buildAppendEvent(args) {
20297
+ return {
20298
+ id: args.idempotencyKey,
20299
+ source: VERIFY_EVENT_SOURCE,
20300
+ type: args.eventType,
20301
+ time: args.at.toISOString(),
20302
+ attempt: VERIFY_APPEND_ATTEMPT,
20303
+ data: {
20304
+ [VERIFY_APPEND_EVENT_FIELD.IDEMPOTENCY_KEY]: args.idempotencyKey,
20305
+ [VERIFY_APPEND_EVENT_FIELD.PAYLOAD]: args.payload
20306
+ }
20307
+ };
20308
+ }
20309
+ var VERIFY_TERMINAL_EVENT_TYPE = `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.terminal`;
20310
+ var VERIFY_TERMINAL_EVENT_FIELD = {
20311
+ TERMINAL_METADATA: "terminalMetadata",
20312
+ TERMINAL_STATUS: "terminalStatus"
20313
+ };
20314
+ var VERIFY_TERMINAL_EVENT_ID_PREFIX = "verify-terminal-";
20315
+ function isVerifyTerminalStatus(value) {
20316
+ return isJournalRunStateStatus(value);
20317
+ }
20318
+ function buildTerminalEvent(args) {
20319
+ return {
20320
+ id: `${VERIFY_TERMINAL_EVENT_ID_PREFIX}${args.runToken}`,
20321
+ source: VERIFY_EVENT_SOURCE,
20322
+ type: VERIFY_TERMINAL_EVENT_TYPE,
20323
+ time: args.at.toISOString(),
20324
+ attempt: VERIFY_APPEND_ATTEMPT,
20325
+ data: {
20326
+ [VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_STATUS]: args.terminalStatus,
20327
+ ...args.terminalMetadata === void 0 ? {} : { [VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_METADATA]: args.terminalMetadata }
20328
+ }
20329
+ };
20330
+ }
20331
+ var VERIFY_NO_EVENTS_SEQUENCE = 0;
20332
+ function findTerminalEvent(events) {
20333
+ return events.find((event) => event.type === VERIFY_TERMINAL_EVENT_TYPE);
20334
+ }
20335
+ function terminalStatusOf(event) {
20336
+ if (event === void 0 || !isJsonRecord(event.data)) return void 0;
20337
+ const status = event.data[VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_STATUS];
20338
+ return typeof status === "string" ? status : void 0;
20339
+ }
20340
+ function terminalMetadataOf(event) {
20341
+ if (event === void 0 || !isJsonRecord(event.data)) return void 0;
20342
+ return event.data[VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_METADATA];
20343
+ }
20344
+ function countVerifyFindings(events) {
20345
+ return events.filter(
20346
+ (event) => event.type === VERIFY_APPEND_EVENT_TYPE.FINDING
20347
+ ).length;
20348
+ }
20349
+ function countReviewScopeFindingUnits(events) {
20350
+ return events.filter((event) => {
20351
+ if (event.type !== VERIFY_APPEND_EVENT_TYPE.SCOPE || !isJsonRecord(event.data)) return false;
20352
+ const payload = event.data[VERIFY_APPEND_EVENT_FIELD.PAYLOAD];
20353
+ const scope2 = validateReviewScope(payload);
20354
+ return scope2?.coverageState === REVIEW_SCOPE_COVERAGE_STATE.FINDING;
20355
+ }).length;
20356
+ }
20357
+ function lastSequenceOf(events) {
20358
+ return events.reduce(
20359
+ (max, event) => event.seq > max ? event.seq : max,
20360
+ VERIFY_NO_EVENTS_SEQUENCE
20361
+ );
20362
+ }
20363
+ function projectVerifyRun(events) {
20364
+ const terminal = findTerminalEvent(events);
20365
+ const terminalStatus = terminalStatusOf(terminal);
20366
+ const terminalMetadata = terminalMetadataOf(terminal);
20367
+ const sealed = terminal !== void 0;
20368
+ return {
20369
+ sealed,
20370
+ ...terminalStatus === void 0 ? {} : { terminalStatus },
20371
+ ...terminalMetadata === void 0 ? {} : { terminalMetadata },
20372
+ findingCount: countVerifyFindings(events),
20373
+ lastSequence: lastSequenceOf(events),
20374
+ nextActions: sealed ? [] : UNSEALED_NEXT_ACTIONS
20375
+ };
20376
+ }
20377
+
20378
+ // src/commands/verify/cli.ts
20379
+ var VERIFY_CLI_EXIT_CODE = {
20380
+ OK: 0,
20381
+ ERROR: 1
20382
+ };
20383
+ var VERIFY_CLI_ENV = {
20384
+ BRANCH: SPX_VERIFY_ENV.BRANCH
20385
+ };
20386
+ var VERIFY_CLI_ERROR = {
20387
+ INPUT_REQUIRED: "spx verification run start requires --input <input-source>",
20388
+ RUN_REQUIRED: "spx verification run existing-run commands require an explicit --run <run-token>",
20389
+ RUN_NOT_FOUND: "spx verification run could not locate the requested run",
20390
+ RUN_SELECTOR_MISMATCH: "spx verification run selector does not match the recorded run",
20391
+ CHANGED_SCOPE_FAILED: "spx verification run could not derive the changeset changed-file scope",
20392
+ INPUT_PERSIST_FAILED: "spx verification run could not persist the recorded run input",
20393
+ INPUT_READ_FAILED: "spx verification run could not read the recorded run input",
20394
+ PAYLOAD_REQUIRED: "spx verification run evidence-add commands require --payload <payload-source>",
20395
+ IDEMPOTENCY_KEY_REQUIRED: "spx verification run evidence-add commands require --idempotency-key <key>",
20396
+ PAYLOAD_READ_FAILED: "spx verification run could not read the evidence payload",
20397
+ PAYLOAD_INVALID: "spx verification run evidence payload is not valid JSON",
20398
+ RUN_FINISHED: "spx verification run cannot add evidence to a finished run",
20399
+ SCOPE_INVALID: "spx verification run scope add payload failed verification-type validation",
20400
+ FINDING_INVALID: "spx verification run finding add payload failed verification-type validation",
20401
+ UNSUPPORTED_VERIFICATION_TYPE: "spx verification run verification type is not registered",
20402
+ APPEND_FAILED: "spx verification run could not append the evidence event",
20403
+ TERMINAL_STATUS_REQUIRED: "spx verification run finish requires --terminal-status <status>",
20404
+ TERMINAL_STATUS_INVALID: "spx verification run finish requires a terminal status in the journal terminal-status vocabulary",
20405
+ TERMINAL_METADATA_INVALID: "spx verification run terminal metadata failed verification-type validation",
20406
+ TERMINAL_STATUS_CONFLICT: "spx verification run terminal status conflicts with verification-type terminal metadata: status-conflict",
20407
+ FINISH_FAILED: "spx verification run could not record terminal completion",
20408
+ SEAL_FAILED: "spx verification run could not seal the run journal",
20409
+ STATUS_FAILED: "spx verification run could not read the run status",
20410
+ RENDER_FAILED: "spx verification run could not render the run projection"
20411
+ };
20412
+ var VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD = {
20413
+ RUN: "run=",
20414
+ VERIFICATION_TYPE: "verification-type=",
20415
+ SCOPE_TYPE: "scope-type=",
20416
+ SCOPE: "scope=",
20417
+ BACKEND: "backend=",
20418
+ NAMESPACE: "namespace=",
20419
+ TARGET: "target="
20420
+ };
20421
+ var VERIFY_START_ROLLBACK_ARTIFACT = {
20422
+ CONTEXT_FILE: "verification context file",
20423
+ RUN_FILE: "journal run file"
20424
+ };
20425
+ function okResult3(output) {
20426
+ return { exitCode: VERIFY_CLI_EXIT_CODE.OK, output };
19729
20427
  }
19730
20428
  function errorResult3(error) {
19731
20429
  return { exitCode: VERIFY_CLI_EXIT_CODE.ERROR, output: error };
@@ -19781,73 +20479,131 @@ async function persistInputRecord(runScope2, record6, deps) {
19781
20479
  const fs8 = deps.fs ?? defaultFileSystem;
19782
20480
  try {
19783
20481
  await fs8.mkdir(dirname12(path7.value), { recursive: true });
19784
- await fs8.writeFile(path7.value, JSON.stringify(record6));
20482
+ await writeFileAtomic(path7.value, JSON.stringify(record6), { fs: fs8, randomBytes: randomBytes2 });
19785
20483
  return { ok: true, value: void 0 };
19786
20484
  } catch (error) {
19787
20485
  return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_PERSIST_FAILED}: ${toMessage2(error)}` };
19788
20486
  }
19789
20487
  }
20488
+ async function readStartInputContent(source, deps) {
20489
+ try {
20490
+ return { ok: true, value: await deps.readInputSource(source) };
20491
+ } catch (error) {
20492
+ return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: ${toMessage2(error)}` };
20493
+ }
20494
+ }
20495
+ async function removeStartedRunArtifact(path7, label, deps) {
20496
+ const fs8 = deps.fs ?? defaultFileSystem;
20497
+ try {
20498
+ await fs8.rm(path7, { force: true });
20499
+ return { ok: true, value: void 0 };
20500
+ } catch (error) {
20501
+ return {
20502
+ ok: false,
20503
+ error: `${VERIFY_CLI_ERROR.INPUT_PERSIST_FAILED}: rollback failed for ${label}: ${toMessage2(error)}`
20504
+ };
20505
+ }
20506
+ }
20507
+ async function removeStartedRunArtifacts(artifacts, deps) {
20508
+ const rollbackErrors = [];
20509
+ if (artifacts.contextPath !== void 0) {
20510
+ const contextRollback = await removeStartedRunArtifact(
20511
+ artifacts.contextPath,
20512
+ VERIFY_START_ROLLBACK_ARTIFACT.CONTEXT_FILE,
20513
+ deps
20514
+ );
20515
+ if (!contextRollback.ok) rollbackErrors.push(contextRollback.error);
20516
+ }
20517
+ if (artifacts.runFile !== void 0) {
20518
+ const runRollback = await removeStartedRunArtifact(
20519
+ artifacts.runFile,
20520
+ VERIFY_START_ROLLBACK_ARTIFACT.RUN_FILE,
20521
+ deps
20522
+ );
20523
+ if (!runRollback.ok) rollbackErrors.push(runRollback.error);
20524
+ }
20525
+ if (rollbackErrors.length > 0) return { ok: false, error: rollbackErrors.join("; ") };
20526
+ return { ok: true, value: void 0 };
20527
+ }
20528
+ function isStoredRecordedInput(value) {
20529
+ if (typeof value !== "object" || value === null) return false;
20530
+ const record6 = value;
20531
+ return typeof record6.scopeIdentity === "string" && typeof record6.scopeType === "string" && typeof record6.source === "string" && typeof record6.digest === "string" && typeof record6.content === "string";
20532
+ }
20533
+ function parseRecordedInput(content) {
20534
+ try {
20535
+ const parsed = JSON.parse(content);
20536
+ if (!isStoredRecordedInput(parsed)) {
20537
+ return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: recorded input is missing required fields` };
20538
+ }
20539
+ return { ok: true, value: parsed };
20540
+ } catch (error) {
20541
+ return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: ${toMessage2(error)}` };
20542
+ }
20543
+ }
19790
20544
  async function readInputRecordAt(path7, deps) {
19791
20545
  const fs8 = deps.fs ?? defaultFileSystem;
20546
+ let content;
19792
20547
  try {
19793
- const content = await fs8.readFile(path7, STATE_STORE_TEXT_ENCODING);
19794
- return { ok: true, value: JSON.parse(content) };
20548
+ content = await fs8.readFile(path7, STATE_STORE_TEXT_ENCODING);
19795
20549
  } catch (error) {
19796
20550
  if (hasErrorCode(error, ERROR_CODE_NOT_FOUND)) return { ok: true, value: void 0 };
19797
20551
  return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: ${toMessage2(error)}` };
19798
20552
  }
20553
+ const parsed = parseRecordedInput(content);
20554
+ if (!parsed.ok) return parsed;
20555
+ return { ok: true, value: parsed.value };
19799
20556
  }
19800
- function verifyRunNotFoundDiagnostic(context) {
20557
+ function verifyRunLocatorDiagnostic(summary, context) {
19801
20558
  return [
19802
- VERIFY_CLI_ERROR.RUN_NOT_FOUND,
19803
- `run=${context.runToken}`,
19804
- `verification-type=${context.verificationType}`,
19805
- `scope-type=${context.scopeType}`,
19806
- `scope=${context.scopeIdentity}`,
19807
- `backend=${context.backendIdentity}`,
19808
- `namespace=${context.storageNamespace}`,
19809
- `target=${context.searchedTarget}`
20559
+ summary,
20560
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.RUN}${context.runToken}`,
20561
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.VERIFICATION_TYPE}${context.verificationType}`,
20562
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.SCOPE_TYPE}${context.scopeType}`,
20563
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.SCOPE}${context.scopeIdentity}`,
20564
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.BACKEND}${context.backendIdentity}`,
20565
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.NAMESPACE}${context.storageNamespace}`,
20566
+ `${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.TARGET}${context.searchedTarget}`
19810
20567
  ].join(" ");
19811
20568
  }
19812
- async function verifyStartCommand(options, deps) {
19813
- if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) return errorResult3(VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE);
19814
- if (options.input.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.INPUT_REQUIRED);
19815
- const scope2 = parseChangesetScope(options.scope);
19816
- if (!scope2.ok) return errorResult3(scope2.error);
19817
- const resolved = await resolveVerifyScope(deps);
19818
- if (!resolved.ok) return errorResult3(resolved.error);
19819
- const inputContent = await deps.readInputSource(options.input);
19820
- const inputDigest = digestRunInput(options.input, inputContent);
19821
- if (!inputDigest.ok) return errorResult3(inputDigest.error);
19822
- const context = await verificationContextCreateCommand(
19823
- {
19824
- subject: VERIFICATION_CONTEXT_SUBJECT_KIND.CHANGESET,
19825
- base: scope2.value.base,
19826
- head: scope2.value.head,
19827
- predicate: options.verificationType,
19828
- workflow: options.verificationType
19829
- },
19830
- forwardDeps(deps)
19831
- );
19832
- if (context.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return errorResult3(context.output);
19833
- const contextDigest = JSON.parse(context.output).digest;
20569
+ function verifyRunNotFoundDiagnostic(context) {
20570
+ return verifyRunLocatorDiagnostic(VERIFY_CLI_ERROR.RUN_NOT_FOUND, context);
20571
+ }
20572
+ async function completeVerifyStartCommand(args) {
20573
+ const { options, deps } = args;
19834
20574
  const opened = await journalOpenCommand(
19835
- { type: options.verificationType, branchSlug: resolved.value.branchSlug },
20575
+ { type: options.verificationType, branchSlug: args.branchSlug },
19836
20576
  forwardDeps(deps)
19837
20577
  );
19838
- if (opened.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return errorResult3(opened.output);
20578
+ if (opened.exitCode !== VERIFY_CLI_EXIT_CODE.OK) {
20579
+ const rollback = await removeStartedRunArtifacts(
20580
+ { ...args.contextCreated ? { contextPath: args.contextPath } : {} },
20581
+ deps
20582
+ );
20583
+ return errorResult3(rollback.ok ? opened.output : `${opened.output}; ${rollback.error}`);
20584
+ }
19839
20585
  const { runToken, runFile } = JSON.parse(opened.output);
19840
20586
  const runScope2 = {
19841
- productDir: resolved.value.productDir,
19842
- branchSlug: resolved.value.branchSlug,
20587
+ productDir: args.productDir,
20588
+ branchSlug: args.branchSlug,
19843
20589
  type: options.verificationType,
19844
20590
  runToken
19845
20591
  };
19846
- const recorded = { source: options.input, digest: inputDigest.value, content: inputContent };
20592
+ const recorded = {
20593
+ scopeIdentity: options.scope,
20594
+ scopeType: options.scopeType,
20595
+ source: options.input,
20596
+ digest: args.inputDigest,
20597
+ content: args.inputContent
20598
+ };
19847
20599
  const persisted = await persistInputRecord(runScope2, recorded, deps);
19848
- if (!persisted.ok) return errorResult3(persisted.error);
19849
- const changedScope = await resolveChangedScope(scope2.value, deps);
19850
- if (!changedScope.ok) return errorResult3(changedScope.error);
20600
+ if (!persisted.ok) {
20601
+ const rollback = await removeStartedRunArtifacts(
20602
+ { ...args.contextCreated ? { contextPath: args.contextPath } : {}, runFile },
20603
+ deps
20604
+ );
20605
+ return errorResult3(rollback.ok ? persisted.error : `${persisted.error}; ${rollback.error}`);
20606
+ }
19851
20607
  const namespace = verifyRunsDir(runScope2);
19852
20608
  if (!namespace.ok) return errorResult3(namespace.error);
19853
20609
  const locator = buildRunLocator({
@@ -19855,52 +20611,69 @@ async function verifyStartCommand(options, deps) {
19855
20611
  verificationType: options.verificationType,
19856
20612
  scopeType: options.scopeType,
19857
20613
  scopeIdentity: options.scope,
19858
- backendIdentity: resolved.value.backendIdentity,
20614
+ backendIdentity: args.backendIdentity,
19859
20615
  storageNamespace: namespace.value,
19860
20616
  runTarget: runFile
19861
20617
  });
19862
20618
  const report2 = {
19863
20619
  runToken,
19864
- contextDigest,
19865
- changedScope: changedScope.value,
19866
- input: { source: options.input, digest: inputDigest.value },
20620
+ contextDigest: args.contextDigest,
20621
+ changedScope: args.changedScope,
20622
+ input: { source: options.input, digest: args.inputDigest },
19867
20623
  locator
19868
20624
  };
19869
20625
  return okResult3(JSON.stringify(report2));
19870
20626
  }
19871
- async function verifyInputCommand(options, deps) {
19872
- if (options.run.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.RUN_REQUIRED);
20627
+ async function verifyStartCommand(options, deps) {
20628
+ if (!isVerifyVerificationType(options.verificationType)) {
20629
+ return errorResult3(VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE);
20630
+ }
20631
+ if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) return errorResult3(VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE);
20632
+ if (options.input.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.INPUT_REQUIRED);
20633
+ const scope2 = parseChangesetScope(options.scope);
20634
+ if (!scope2.ok) return errorResult3(scope2.error);
19873
20635
  const resolved = await resolveVerifyScope(deps);
19874
20636
  if (!resolved.ok) return errorResult3(resolved.error);
19875
- const runScope2 = {
20637
+ const inputContent = await readStartInputContent(options.input, deps);
20638
+ if (!inputContent.ok) return errorResult3(inputContent.error);
20639
+ const inputDigest = digestRunInput(options.input, inputContent.value);
20640
+ if (!inputDigest.ok) return errorResult3(inputDigest.error);
20641
+ const changedScope = await resolveChangedScope(scope2.value, deps);
20642
+ if (!changedScope.ok) return errorResult3(changedScope.error);
20643
+ const context = await verificationContextCreateCommand(
20644
+ {
20645
+ subject: VERIFICATION_CONTEXT_SUBJECT_KIND.CHANGESET,
20646
+ base: scope2.value.base,
20647
+ head: scope2.value.head,
20648
+ predicate: options.verificationType,
20649
+ workflow: options.verificationType
20650
+ },
20651
+ forwardDeps(deps)
20652
+ );
20653
+ if (context.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return errorResult3(context.output);
20654
+ const { digest: contextDigest, contextPath, created: contextCreated } = JSON.parse(context.output);
20655
+ return completeVerifyStartCommand({
20656
+ options,
20657
+ deps,
19876
20658
  productDir: resolved.value.productDir,
19877
20659
  branchSlug: resolved.value.branchSlug,
19878
- type: options.verificationType,
19879
- runToken: options.run
19880
- };
19881
- const path7 = verifyInputRecordPath(runScope2);
19882
- if (!path7.ok) return errorResult3(path7.error);
19883
- const namespace = verifyRunsDir(runScope2);
19884
- if (!namespace.ok) return errorResult3(namespace.error);
19885
- const record6 = await readInputRecordAt(path7.value, deps);
19886
- if (!record6.ok) return errorResult3(record6.error);
19887
- if (record6.value === void 0) {
19888
- return errorResult3(
19889
- verifyRunNotFoundDiagnostic({
19890
- runToken: options.run,
19891
- verificationType: options.verificationType,
19892
- scopeType: options.scopeType,
19893
- scopeIdentity: options.scope,
19894
- backendIdentity: resolved.value.backendIdentity,
19895
- storageNamespace: namespace.value,
19896
- searchedTarget: path7.value
19897
- })
19898
- );
19899
- }
20660
+ backendIdentity: resolved.value.backendIdentity,
20661
+ changedScope: changedScope.value,
20662
+ inputDigest: inputDigest.value,
20663
+ inputContent: inputContent.value,
20664
+ contextDigest,
20665
+ contextPath,
20666
+ contextCreated
20667
+ });
20668
+ }
20669
+ async function verifyInputCommand(options, deps) {
20670
+ const run = await resolveExistingRun(options, deps);
20671
+ if (!run.ok) return errorResult3(run.error);
20672
+ const record6 = run.value.recordedInput;
19900
20673
  const report2 = {
19901
- source: record6.value.source,
19902
- digest: record6.value.digest,
19903
- content: record6.value.content
20674
+ source: record6.source,
20675
+ digest: record6.digest,
20676
+ content: record6.content
19904
20677
  };
19905
20678
  return okResult3(JSON.stringify(report2));
19906
20679
  }
@@ -19909,12 +20682,36 @@ async function readRunJournalEvents(scope2, deps) {
19909
20682
  if (read.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return { ok: false, error: read.output };
19910
20683
  return { ok: true, value: JSON.parse(read.output) };
19911
20684
  }
20685
+ async function readAppendExistingEvents(options, deps, journalScope, backendIdentity, namespace) {
20686
+ const existingEvents = await readRunJournalEvents(journalScope, deps);
20687
+ if (!existingEvents.ok) {
20688
+ if (existingEvents.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
20689
+ return {
20690
+ ok: false,
20691
+ error: appendRunNotFoundDiagnostic(options, backendIdentity, namespace)
20692
+ };
20693
+ }
20694
+ return { ok: false, error: `${VERIFY_CLI_ERROR.APPEND_FAILED}: ${existingEvents.error}` };
20695
+ }
20696
+ if (findTerminalEvent(existingEvents.value) !== void 0) {
20697
+ return { ok: false, error: VERIFY_CLI_ERROR.RUN_FINISHED };
20698
+ }
20699
+ return existingEvents;
20700
+ }
19912
20701
  async function prepareAppend(options, deps) {
19913
20702
  if (options.run.trim().length === 0) return { ok: false, error: VERIFY_CLI_ERROR.RUN_REQUIRED };
20703
+ if (!isVerifyVerificationType(options.verificationType)) {
20704
+ return { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
20705
+ }
19914
20706
  if (options.payload.trim().length === 0) return { ok: false, error: VERIFY_CLI_ERROR.PAYLOAD_REQUIRED };
19915
20707
  if (options.idempotencyKey.trim().length === 0) {
19916
20708
  return { ok: false, error: VERIFY_CLI_ERROR.IDEMPOTENCY_KEY_REQUIRED };
19917
20709
  }
20710
+ if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) {
20711
+ return { ok: false, error: VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE };
20712
+ }
20713
+ const scope2 = parseChangesetScope(options.scope);
20714
+ if (!scope2.ok) return scope2;
19918
20715
  const readPayload = deps.readPayloadSource;
19919
20716
  const binding = deps.journalBinding;
19920
20717
  if (readPayload === void 0 || binding === void 0) return { ok: false, error: VERIFY_CLI_ERROR.APPEND_FAILED };
@@ -19928,25 +20725,53 @@ async function prepareAppend(options, deps) {
19928
20725
  };
19929
20726
  const namespace = verifyRunsDir(runScope2);
19930
20727
  if (!namespace.ok) return namespace;
20728
+ const journalScope = {
20729
+ type: options.verificationType,
20730
+ runToken: options.run,
20731
+ branchSlug: resolved.value.branchSlug
20732
+ };
20733
+ const existingEvents = await readAppendExistingEvents(
20734
+ options,
20735
+ deps,
20736
+ journalScope,
20737
+ resolved.value.backendIdentity,
20738
+ namespace.value
20739
+ );
20740
+ if (!existingEvents.ok) return existingEvents;
19931
20741
  const inputPath = verifyInputRecordPath(runScope2);
19932
20742
  if (!inputPath.ok) return inputPath;
19933
20743
  const inputRecord = await readInputRecordAt(inputPath.value, deps);
19934
20744
  if (!inputRecord.ok) return inputRecord;
19935
20745
  if (inputRecord.value === void 0) {
19936
- return { ok: false, error: appendRunNotFoundDiagnostic(options, resolved.value.backendIdentity, namespace.value) };
20746
+ return {
20747
+ ok: false,
20748
+ error: appendRunNotFoundDiagnostic(options, resolved.value.backendIdentity, namespace.value, inputPath.value)
20749
+ };
20750
+ }
20751
+ if (!recordedSelectorMatches(inputRecord.value, options)) {
20752
+ return {
20753
+ ok: false,
20754
+ error: appendRunSelectorMismatchDiagnostic(
20755
+ options,
20756
+ resolved.value.backendIdentity,
20757
+ namespace.value,
20758
+ inputPath.value
20759
+ )
20760
+ };
19937
20761
  }
19938
20762
  return {
19939
20763
  ok: true,
19940
20764
  value: {
19941
20765
  readPayload,
19942
20766
  binding,
19943
- journalScope: { type: options.verificationType, runToken: options.run, branchSlug: resolved.value.branchSlug },
20767
+ journalScope,
19944
20768
  namespace: namespace.value,
19945
- backendIdentity: resolved.value.backendIdentity
20769
+ backendIdentity: resolved.value.backendIdentity,
20770
+ existingEvents: existingEvents.value
19946
20771
  }
19947
20772
  };
19948
20773
  }
19949
- function appendRunNotFoundDiagnostic(options, backendIdentity, namespace) {
20774
+ function appendRunNotFoundDiagnostic(options, backendIdentity, namespace, searchedTarget = namespace) {
19950
20775
  return verifyRunNotFoundDiagnostic({
19951
20776
  runToken: options.run,
19952
20777
  verificationType: options.verificationType,
@@ -19954,15 +20779,32 @@ function appendRunNotFoundDiagnostic(options, backendIdentity, namespace) {
19954
20779
  scopeIdentity: options.scope,
19955
20780
  backendIdentity,
19956
20781
  storageNamespace: namespace,
19957
- searchedTarget: namespace
20782
+ searchedTarget
19958
20783
  });
19959
20784
  }
19960
- function validateAppendFinding(verb, verificationType, payload) {
19961
- if (verb !== VERIFY_VERB.APPEND_FINDING) return void 0;
19962
- const validator = findingValidatorFor(verificationType);
19963
- if (validator === void 0) return VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE;
19964
- if (validator(payload) === void 0) return VERIFY_CLI_ERROR.FINDING_INVALID;
19965
- return void 0;
20785
+ function appendRunSelectorMismatchDiagnostic(options, backendIdentity, namespace, searchedTarget) {
20786
+ return verifyRunLocatorDiagnostic(VERIFY_CLI_ERROR.RUN_SELECTOR_MISMATCH, {
20787
+ runToken: options.run,
20788
+ verificationType: options.verificationType,
20789
+ scopeType: options.scopeType,
20790
+ scopeIdentity: options.scope,
20791
+ backendIdentity,
20792
+ storageNamespace: namespace,
20793
+ searchedTarget
20794
+ });
20795
+ }
20796
+ function validateAppendEvidence(verb, verificationType, payload, events) {
20797
+ const evidenceKind = verb === VERIFY_VERB.APPEND_FINDING ? VERIFY_EVIDENCE_KIND.FINDING : VERIFY_EVIDENCE_KIND.SCOPE;
20798
+ const validator = evidenceValidatorFor(verificationType, evidenceKind);
20799
+ if (validator === void 0) return { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
20800
+ const validated = validator({ payload, events });
20801
+ if (validated === void 0) {
20802
+ return {
20803
+ ok: false,
20804
+ error: verb === VERIFY_VERB.APPEND_FINDING ? VERIFY_CLI_ERROR.FINDING_INVALID : VERIFY_CLI_ERROR.SCOPE_INVALID
20805
+ };
20806
+ }
20807
+ return { ok: true, value: JSON.parse(JSON.stringify(validated)) };
19966
20808
  }
19967
20809
  function appendEventType(verb) {
19968
20810
  return verb === VERIFY_VERB.APPEND_FINDING ? VERIFY_APPEND_EVENT_TYPE.FINDING : VERIFY_APPEND_EVENT_TYPE.SCOPE;
@@ -19970,16 +20812,9 @@ function appendEventType(verb) {
19970
20812
  async function verifyAppend(options, deps, verb) {
19971
20813
  const prepared = await prepareAppend(options, deps);
19972
20814
  if (!prepared.ok) return errorResult3(prepared.error);
19973
- const { readPayload, binding, journalScope, namespace, backendIdentity } = prepared.value;
20815
+ const { readPayload, binding, journalScope, existingEvents } = prepared.value;
19974
20816
  const eventType = appendEventType(verb);
19975
- const before = await readRunJournalEvents(journalScope, deps);
19976
- if (!before.ok) {
19977
- if (before.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
19978
- return errorResult3(appendRunNotFoundDiagnostic(options, backendIdentity, namespace));
19979
- }
19980
- return errorResult3(`${VERIFY_CLI_ERROR.APPEND_FAILED}: ${before.error}`);
19981
- }
19982
- const existing = findAppendedSequence(before.value, options.idempotencyKey, eventType);
20817
+ const existing = findAppendedSequence(existingEvents, options.idempotencyKey, eventType);
19983
20818
  if (existing !== void 0) {
19984
20819
  const report3 = { sequence: existing, idempotent: true };
19985
20820
  return okResult3(JSON.stringify(report3));
@@ -19992,12 +20827,12 @@ async function verifyAppend(options, deps, verb) {
19992
20827
  }
19993
20828
  const parsed = parseAppendPayload(rawPayload);
19994
20829
  if (parsed === void 0) return errorResult3(VERIFY_CLI_ERROR.PAYLOAD_INVALID);
19995
- const findingError = validateAppendFinding(verb, options.verificationType, parsed);
19996
- if (findingError !== void 0) return errorResult3(findingError);
20830
+ const evidence = validateAppendEvidence(verb, options.verificationType, parsed, existingEvents);
20831
+ if (!evidence.ok) return errorResult3(evidence.error);
19997
20832
  const event = buildAppendEvent({
19998
20833
  eventType,
19999
20834
  idempotencyKey: options.idempotencyKey,
20000
- payload: parsed,
20835
+ payload: evidence.value,
20001
20836
  at: deps.now?.() ?? /* @__PURE__ */ new Date()
20002
20837
  });
20003
20838
  const appended = await journalAppendCommand(journalScope, event, binding, forwardDeps(deps));
@@ -20017,24 +20852,309 @@ async function verifyAppendScopeCommand(options, deps) {
20017
20852
  async function verifyAppendFindingCommand(options, deps) {
20018
20853
  return verifyAppend(options, deps, VERIFY_VERB.APPEND_FINDING);
20019
20854
  }
20855
+ function existingRunNotFound(run, options) {
20856
+ return verifyRunNotFoundDiagnostic({
20857
+ runToken: run.runToken,
20858
+ verificationType: options.verificationType,
20859
+ scopeType: options.scopeType,
20860
+ scopeIdentity: options.scope,
20861
+ backendIdentity: run.backendIdentity,
20862
+ storageNamespace: run.namespace,
20863
+ searchedTarget: run.inputRecordPath
20864
+ });
20865
+ }
20866
+ function existingRunSelectorMismatch(run, options) {
20867
+ return verifyRunLocatorDiagnostic(VERIFY_CLI_ERROR.RUN_SELECTOR_MISMATCH, {
20868
+ runToken: run.runToken,
20869
+ verificationType: options.verificationType,
20870
+ scopeType: options.scopeType,
20871
+ scopeIdentity: options.scope,
20872
+ backendIdentity: run.backendIdentity,
20873
+ storageNamespace: run.namespace,
20874
+ searchedTarget: run.inputRecordPath
20875
+ });
20876
+ }
20877
+ function recordedSelectorMatches(record6, options) {
20878
+ return record6.scopeType === options.scopeType && record6.scopeIdentity === options.scope;
20879
+ }
20880
+ async function readExistingRecordedInput(run, deps) {
20881
+ return readInputRecordAt(run.inputRecordPath, deps);
20882
+ }
20883
+ async function resolveExistingRunAddress(options, deps) {
20884
+ if (!isVerifyVerificationType(options.verificationType)) {
20885
+ return { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
20886
+ }
20887
+ if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) {
20888
+ return { ok: false, error: VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE };
20889
+ }
20890
+ const scope2 = parseChangesetScope(options.scope);
20891
+ if (!scope2.ok) return scope2;
20892
+ if (options.run.trim().length === 0) return { ok: false, error: VERIFY_CLI_ERROR.RUN_REQUIRED };
20893
+ const resolved = await resolveVerifyScope(deps);
20894
+ if (!resolved.ok) return resolved;
20895
+ const runScope2 = {
20896
+ productDir: resolved.value.productDir,
20897
+ branchSlug: resolved.value.branchSlug,
20898
+ type: options.verificationType,
20899
+ runToken: options.run
20900
+ };
20901
+ const namespace = verifyRunsDir(runScope2);
20902
+ if (!namespace.ok) return namespace;
20903
+ const inputPath = verifyInputRecordPath(runScope2);
20904
+ if (!inputPath.ok) return inputPath;
20905
+ return {
20906
+ ok: true,
20907
+ value: {
20908
+ productDir: resolved.value.productDir,
20909
+ runToken: options.run,
20910
+ journalScope: { type: options.verificationType, runToken: options.run, branchSlug: resolved.value.branchSlug },
20911
+ namespace: namespace.value,
20912
+ backendIdentity: resolved.value.backendIdentity,
20913
+ inputRecordPath: inputPath.value
20914
+ }
20915
+ };
20916
+ }
20917
+ async function resolveExistingRun(options, deps) {
20918
+ const address = await resolveExistingRunAddress(options, deps);
20919
+ if (!address.ok) return address;
20920
+ const inputRecord = await readExistingRecordedInput(address.value, deps);
20921
+ if (!inputRecord.ok) return inputRecord;
20922
+ if (inputRecord.value === void 0) {
20923
+ return { ok: false, error: existingRunNotFound(address.value, options) };
20924
+ }
20925
+ if (!recordedSelectorMatches(inputRecord.value, options)) {
20926
+ return { ok: false, error: existingRunSelectorMismatch(address.value, options) };
20927
+ }
20928
+ const run = { ...address.value, recordedInput: inputRecord.value };
20929
+ return { ok: true, value: run };
20930
+ }
20931
+ function isRecordedInputReadFailure(error) {
20932
+ return error.startsWith(VERIFY_CLI_ERROR.INPUT_READ_FAILED);
20933
+ }
20934
+ async function readRecordedInputForProjection(run, options, events, deps) {
20935
+ const terminal = findTerminalEvent(events);
20936
+ const inputRecord = await readExistingRecordedInput(run, deps);
20937
+ if (!inputRecord.ok) {
20938
+ if (terminal !== void 0 && isRecordedInputReadFailure(inputRecord.error)) {
20939
+ return { ok: true, value: void 0 };
20940
+ }
20941
+ return inputRecord;
20942
+ }
20943
+ if (inputRecord.value === void 0) return { ok: true, value: void 0 };
20944
+ if (!recordedSelectorMatches(inputRecord.value, options)) {
20945
+ return { ok: false, error: existingRunSelectorMismatch(run, options) };
20946
+ }
20947
+ return { ok: true, value: inputRecord.value };
20948
+ }
20949
+ function verifyFinishReport(runToken, projection) {
20950
+ return {
20951
+ runToken,
20952
+ ...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
20953
+ ...projection.terminalMetadata === void 0 ? {} : { terminalMetadata: projection.terminalMetadata },
20954
+ sealed: projection.sealed,
20955
+ findingCount: projection.findingCount,
20956
+ lastSequence: projection.lastSequence
20957
+ };
20958
+ }
20959
+ async function isJournalPhysicallySealed(run, deps) {
20960
+ return isJournalRunSealed(
20961
+ { ...run.journalScope, productDir: run.productDir },
20962
+ { ...deps.fs === void 0 ? {} : { fs: deps.fs } }
20963
+ );
20964
+ }
20965
+ async function sealExistingRun(run, deps) {
20966
+ const sealed = await journalSealCommand(run.journalScope, forwardDeps(deps));
20967
+ if (sealed.exitCode !== VERIFY_CLI_EXIT_CODE.OK) {
20968
+ return errorResult3(`${VERIFY_CLI_ERROR.SEAL_FAILED}: ${sealed.output}`);
20969
+ }
20970
+ return void 0;
20971
+ }
20972
+ function finishReadFailure(run, options, error) {
20973
+ if (error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
20974
+ return errorResult3(existingRunNotFound(run, options));
20975
+ }
20976
+ return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${error}`);
20977
+ }
20978
+ async function readTerminalMetadata(options, deps) {
20979
+ if (options.terminalMetadata === void 0) return { ok: true, value: void 0 };
20980
+ const readPayload = deps.readPayloadSource;
20981
+ if (readPayload === void 0) return { ok: false, error: VERIFY_CLI_ERROR.TERMINAL_METADATA_INVALID };
20982
+ try {
20983
+ const rawMetadata = await readPayload(options.terminalMetadata);
20984
+ const parsed = parseAppendPayload(rawMetadata);
20985
+ if (parsed === void 0) return { ok: false, error: VERIFY_CLI_ERROR.PAYLOAD_INVALID };
20986
+ return { ok: true, value: parsed };
20987
+ } catch (error) {
20988
+ return { ok: false, error: `${VERIFY_CLI_ERROR.PAYLOAD_READ_FAILED}: ${toMessage2(error)}` };
20989
+ }
20990
+ }
20991
+ function validateTerminalMetadata(verificationType, terminalStatus, metadata, events) {
20992
+ const validator = terminalMetadataValidatorFor(verificationType);
20993
+ if (validator === void 0) {
20994
+ return metadata === void 0 ? { ok: true, value: void 0 } : { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
20995
+ }
20996
+ const validated = validator({ terminalStatus, metadata, events });
20997
+ if (validated.ok) return { ok: true, value: validated.value };
20998
+ return {
20999
+ ok: false,
21000
+ error: validated.error === TERMINAL_METADATA_VALIDATION_ERROR.STATUS_CONFLICT ? VERIFY_CLI_ERROR.TERMINAL_STATUS_CONFLICT : VERIFY_CLI_ERROR.TERMINAL_METADATA_INVALID
21001
+ };
21002
+ }
21003
+ async function finishProjectionResult(run, deps) {
21004
+ const events = await readRunJournalEvents(run.journalScope, deps);
21005
+ if (!events.ok) return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${events.error}`);
21006
+ return okResult3(JSON.stringify(verifyFinishReport(run.runToken, projectVerifyRun(events.value))));
21007
+ }
21008
+ async function retrySealForTerminalRun(run, deps) {
21009
+ const physicallySealed = await isJournalPhysicallySealed(run, deps);
21010
+ if (!physicallySealed.ok) return void 0;
21011
+ if (physicallySealed.value) return void 0;
21012
+ return sealExistingRun(run, deps);
21013
+ }
21014
+ async function verifyFinishCommand(options, deps) {
21015
+ if (options.terminalStatus.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.TERMINAL_STATUS_REQUIRED);
21016
+ if (!isVerifyTerminalStatus(options.terminalStatus)) return errorResult3(VERIFY_CLI_ERROR.TERMINAL_STATUS_INVALID);
21017
+ const run = await resolveExistingRunAddress(options, deps);
21018
+ if (!run.ok) return errorResult3(run.error);
21019
+ const before = await readRunJournalEvents(run.value.journalScope, deps);
21020
+ if (!before.ok) {
21021
+ return finishReadFailure(run.value, options, before.error);
21022
+ }
21023
+ const inputRecord = await readRecordedInputForProjection(run.value, options, before.value, deps);
21024
+ if (!inputRecord.ok) return errorResult3(inputRecord.error);
21025
+ if (findTerminalEvent(before.value) !== void 0) {
21026
+ const retrySeal = await retrySealForTerminalRun(run.value, deps);
21027
+ return retrySeal ?? finishProjectionResult(run.value, deps);
21028
+ }
21029
+ if (inputRecord.value === void 0) {
21030
+ return errorResult3(existingRunNotFound(run.value, options));
21031
+ }
21032
+ const rawTerminalMetadata = await readTerminalMetadata(options, deps);
21033
+ if (!rawTerminalMetadata.ok) return errorResult3(rawTerminalMetadata.error);
21034
+ const terminalMetadata = validateTerminalMetadata(
21035
+ options.verificationType,
21036
+ options.terminalStatus,
21037
+ rawTerminalMetadata.value,
21038
+ before.value
21039
+ );
21040
+ if (!terminalMetadata.ok) return errorResult3(terminalMetadata.error);
21041
+ const binding = deps.journalBinding;
21042
+ if (binding === void 0) return errorResult3(VERIFY_CLI_ERROR.FINISH_FAILED);
21043
+ const event = buildTerminalEvent({
21044
+ runToken: run.value.runToken,
21045
+ terminalStatus: options.terminalStatus,
21046
+ ...terminalMetadata.value === void 0 ? {} : { terminalMetadata: terminalMetadata.value },
21047
+ at: deps.now?.() ?? /* @__PURE__ */ new Date()
21048
+ });
21049
+ const appended = await journalAppendCommand(run.value.journalScope, event, binding, forwardDeps(deps));
21050
+ if (appended.exitCode !== VERIFY_CLI_EXIT_CODE.OK) {
21051
+ return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${appended.output}`);
21052
+ }
21053
+ const sealResult = await sealExistingRun(run.value, deps);
21054
+ if (sealResult !== void 0) return sealResult;
21055
+ return finishProjectionResult(run.value, deps);
21056
+ }
21057
+ async function verifyStatusCommand(options, deps) {
21058
+ const run = await resolveExistingRunAddress(options, deps);
21059
+ if (!run.ok) return errorResult3(run.error);
21060
+ const events = await readRunJournalEvents(run.value.journalScope, deps);
21061
+ if (!events.ok) {
21062
+ if (events.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
21063
+ return errorResult3(existingRunNotFound(run.value, options));
21064
+ }
21065
+ return errorResult3(`${VERIFY_CLI_ERROR.STATUS_FAILED}: ${events.error}`);
21066
+ }
21067
+ const inputRecord = await readRecordedInputForProjection(run.value, options, events.value, deps);
21068
+ if (!inputRecord.ok) return errorResult3(inputRecord.error);
21069
+ if (inputRecord.value === void 0 && findTerminalEvent(events.value) === void 0) {
21070
+ return errorResult3(existingRunNotFound(run.value, options));
21071
+ }
21072
+ const projection = projectVerifyRun(events.value);
21073
+ const report2 = {
21074
+ runToken: run.value.runToken,
21075
+ verificationType: options.verificationType,
21076
+ scopeType: options.scopeType,
21077
+ sealed: projection.sealed,
21078
+ lastSequence: projection.lastSequence,
21079
+ ...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
21080
+ ...projection.terminalMetadata === void 0 ? {} : { terminalMetadata: projection.terminalMetadata },
21081
+ findingCount: projection.findingCount,
21082
+ nextActions: projection.nextActions
21083
+ };
21084
+ return okResult3(JSON.stringify(report2));
21085
+ }
21086
+ async function verifyRenderCommand(options, deps) {
21087
+ const run = await resolveExistingRunAddress(options, deps);
21088
+ if (!run.ok) return errorResult3(run.error);
21089
+ const events = await readRunJournalEvents(run.value.journalScope, deps);
21090
+ if (!events.ok) {
21091
+ if (events.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
21092
+ return errorResult3(existingRunNotFound(run.value, options));
21093
+ }
21094
+ return errorResult3(`${VERIFY_CLI_ERROR.RENDER_FAILED}: ${events.error}`);
21095
+ }
21096
+ const inputRecord = await readRecordedInputForProjection(run.value, options, events.value, deps);
21097
+ if (!inputRecord.ok) return errorResult3(inputRecord.error);
21098
+ if (inputRecord.value === void 0 && findTerminalEvent(events.value) === void 0) {
21099
+ return errorResult3(existingRunNotFound(run.value, options));
21100
+ }
21101
+ const projection = projectVerifyRun(events.value);
21102
+ const report2 = {
21103
+ runToken: run.value.runToken,
21104
+ findingCount: projection.findingCount,
21105
+ sealed: projection.sealed,
21106
+ ...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
21107
+ ...projection.terminalMetadata === void 0 ? {} : { terminalMetadata: projection.terminalMetadata },
21108
+ events: events.value
21109
+ };
21110
+ return okResult3(JSON.stringify(report2));
21111
+ }
20020
21112
 
20021
21113
  // src/interfaces/cli/verify.ts
21114
+ var VERIFICATION_RUN_CLI_SURFACE = {
21115
+ addCommandName: "add",
21116
+ findingResourceCommandName: "finding",
21117
+ forbiddenRootCommandName: "verify",
21118
+ forbiddenRunHelpTerms: ["Append", "append"],
21119
+ forbiddenRunCommandNames: ["journal", "event", "append-scope", "append-finding"],
21120
+ rootCommandName: "verification",
21121
+ runCommandName: "run",
21122
+ scopeResourceCommandName: "scope"
21123
+ };
20022
21124
  var VERIFY_CLI = {
20023
- commandName: "verify",
21125
+ addCommandName: VERIFICATION_RUN_CLI_SURFACE.addCommandName,
21126
+ commandName: VERIFICATION_RUN_CLI_SURFACE.rootCommandName,
20024
21127
  description: "Record and replay a typed verification run",
20025
21128
  startCommandName: VERIFY_VERB.START,
20026
21129
  inputCommandName: VERIFY_VERB.INPUT,
20027
- appendScopeCommandName: VERIFY_VERB.APPEND_SCOPE,
20028
- appendFindingCommandName: VERIFY_VERB.APPEND_FINDING,
21130
+ findingCommandName: VERIFICATION_RUN_CLI_SURFACE.findingResourceCommandName,
21131
+ runCommandName: VERIFICATION_RUN_CLI_SURFACE.runCommandName,
21132
+ scopeCommandName: VERIFICATION_RUN_CLI_SURFACE.scopeResourceCommandName,
21133
+ finishCommandName: VERIFY_VERB.FINISH,
21134
+ statusCommandName: VERIFY_VERB.STATUS,
21135
+ renderCommandName: VERIFY_VERB.RENDER,
20029
21136
  verificationTypeOption: "--verification-type <type>",
20030
21137
  scopeTypeOption: "--scope-type <scope-type>",
20031
21138
  scopeOption: "--scope <base>..<head>",
20032
21139
  inputOption: "--input <input-source>",
20033
21140
  runOption: "--run <token>",
20034
21141
  payloadOption: "--payload <payload-source>",
20035
- idempotencyKeyOption: "--idempotency-key <key>"
21142
+ payloadOptionDescription: "Evidence payload source; stdin or a file path",
21143
+ idempotencyKeyOption: "--idempotency-key <key>",
21144
+ idempotencyKeyOptionDescription: "Caller-supplied idempotency key for the evidence add",
21145
+ terminalMetadataOption: "--terminal-metadata <payload-source>",
21146
+ terminalStatusOption: "--terminal-status <status>"
20036
21147
  };
20037
21148
  var CLI_SOURCE_ENCODING = "utf8";
21149
+ var DEFAULT_VERIFY_CLI_HANDLERS = {
21150
+ appendFinding: verifyAppendFindingCommand,
21151
+ appendScope: verifyAppendScopeCommand,
21152
+ finish: verifyFinishCommand,
21153
+ input: verifyInputCommand,
21154
+ render: verifyRenderCommand,
21155
+ start: verifyStartCommand,
21156
+ status: verifyStatusCommand
21157
+ };
20038
21158
  async function readStdinText() {
20039
21159
  const chunks = [];
20040
21160
  for await (const chunk of process.stdin) {
@@ -20049,30 +21169,43 @@ async function readCliSource(source) {
20049
21169
  var verifyDomain = {
20050
21170
  name: VERIFY_CLI.commandName,
20051
21171
  description: VERIFY_CLI.description,
20052
- register: (program, invocation) => {
20053
- const deps = () => ({
20054
- cwd: invocation.resolveEffectiveInvocationDir(),
20055
- readInputSource: readCliSource,
20056
- readPayloadSource: readCliSource,
20057
- // The append verbs write a single structured JSON result to stdout, so the run's event
20058
- // stream goes to stderr under the local backend rather than sharing the result channel.
20059
- journalBinding: createJournalStreamBinding(invocation.io, stderrStreamSink(invocation.io))
20060
- });
20061
- const command = program.command(VERIFY_CLI.commandName).description(VERIFY_CLI.description);
20062
- command.command(VERIFY_CLI.startCommandName).description("Start a changeset-scoped verification run and report its run locator").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.inputOption, "Verification input source; stdin or a file path").action(async (options) => {
20063
- reportCliResult(await verifyStartCommand(options, deps()), invocation.io);
20064
- });
20065
- command.command(VERIFY_CLI.inputCommandName).description("Replay the verification input recorded at start").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
20066
- reportCliResult(await verifyInputCommand(options, deps()), invocation.io);
20067
- });
20068
- command.command(VERIFY_CLI.appendScopeCommandName).description("Record the inspected scope for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, "Append payload source; stdin or a file path").requiredOption(VERIFY_CLI.idempotencyKeyOption, "Caller-supplied idempotency key for the append").action(async (options) => {
20069
- reportCliResult(await verifyAppendScopeCommand(options, deps()), invocation.io);
20070
- });
20071
- command.command(VERIFY_CLI.appendFindingCommandName).description("Record a validated verification finding for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, "Append payload source; stdin or a file path").requiredOption(VERIFY_CLI.idempotencyKeyOption, "Caller-supplied idempotency key for the append").action(async (options) => {
20072
- reportCliResult(await verifyAppendFindingCommand(options, deps()), invocation.io);
20073
- });
20074
- }
20075
- };
21172
+ register: (program, invocation) => registerVerifyCommands(program, invocation)
21173
+ };
21174
+ function registerVerifyCommands(program, invocation, handlers = DEFAULT_VERIFY_CLI_HANDLERS) {
21175
+ const deps = () => ({
21176
+ cwd: invocation.resolveEffectiveInvocationDir(),
21177
+ readInputSource: readCliSource,
21178
+ readPayloadSource: readCliSource,
21179
+ // The append verbs write a single structured JSON result to stdout, so the run's event
21180
+ // stream goes to stderr under the local backend rather than sharing the result channel.
21181
+ journalBinding: createJournalStreamBinding(invocation.io, stderrStreamSink(invocation.io))
21182
+ });
21183
+ const command = program.command(VERIFY_CLI.commandName).description(VERIFY_CLI.description);
21184
+ const runCommand = command.command(VERIFY_CLI.runCommandName).description("Manage a typed verification run lifecycle");
21185
+ runCommand.command(VERIFY_CLI.startCommandName).description("Start a changeset-scoped verification run and report its run locator").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.inputOption, "Verification input source; stdin or a file path").action(async (options) => {
21186
+ reportCliResult(await handlers.start(options, deps()), invocation.io);
21187
+ });
21188
+ runCommand.command(VERIFY_CLI.inputCommandName).description("Replay the verification input recorded at start").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
21189
+ reportCliResult(await handlers.input(options, deps()), invocation.io);
21190
+ });
21191
+ const scopeCommand = runCommand.command(VERIFY_CLI.scopeCommandName).description("Manage inspected scope evidence for a started verification run");
21192
+ scopeCommand.command(VERIFY_CLI.addCommandName).description("Record the inspected scope for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, VERIFY_CLI.payloadOptionDescription).requiredOption(VERIFY_CLI.idempotencyKeyOption, VERIFY_CLI.idempotencyKeyOptionDescription).action(async (options) => {
21193
+ reportCliResult(await handlers.appendScope(options, deps()), invocation.io);
21194
+ });
21195
+ const findingCommand = runCommand.command(VERIFY_CLI.findingCommandName).description("Manage finding evidence for a started verification run");
21196
+ findingCommand.command(VERIFY_CLI.addCommandName).description("Record a validated verification finding for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, VERIFY_CLI.payloadOptionDescription).requiredOption(VERIFY_CLI.idempotencyKeyOption, VERIFY_CLI.idempotencyKeyOptionDescription).action(async (options) => {
21197
+ reportCliResult(await handlers.appendFinding(options, deps()), invocation.io);
21198
+ });
21199
+ runCommand.command(VERIFY_CLI.finishCommandName).description("Record terminal completion, seal the run journal, and report its terminal projection").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.terminalStatusOption, "Terminal status recorded before sealing").option(VERIFY_CLI.terminalMetadataOption, "Verification-type terminal metadata source; stdin or a file path").action(async (options) => {
21200
+ reportCliResult(await handlers.finish(options, deps()), invocation.io);
21201
+ });
21202
+ runCommand.command(VERIFY_CLI.statusCommandName).description("Report the run's resumable status projected from its journal history").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
21203
+ reportCliResult(await handlers.status(options, deps()), invocation.io);
21204
+ });
21205
+ runCommand.command(VERIFY_CLI.renderCommandName).description("Render the run's journal projection with its authoritative finding count").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
21206
+ reportCliResult(await handlers.render(options, deps()), invocation.io);
21207
+ });
21208
+ }
20076
21209
 
20077
21210
  // src/interfaces/cli/worktree.ts
20078
21211
  import { randomBytes as nodeRandomBytes4 } from "crypto";