@outcomeeng/spx 0.6.12 → 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.
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 };
@@ -3014,6 +3081,7 @@ var AGENT = {
3014
3081
  CLAUDE_CODE: "claudeCode"
3015
3082
  };
3016
3083
  var HARNESS_ENVIRONMENT_CONFIG_FIELDS = {
3084
+ METHODOLOGY: "methodology",
3017
3085
  INSTRUCTIONS: "instructions",
3018
3086
  AGENTS: "agents",
3019
3087
  PLUGIN_BOOTSTRAP: "pluginBootstrap",
@@ -3033,6 +3101,8 @@ var HARNESS_ENVIRONMENT_CONFIG_FIELDS = {
3033
3101
  VERSION: "version",
3034
3102
  MARKETPLACE: "marketplace"
3035
3103
  };
3104
+ var DEFAULT_METHODOLOGY_SOURCE = "outcomeeng/spec-tree";
3105
+ var DEFAULT_METHODOLOGY_VERSION = "installed";
3036
3106
  var AGENT_SET = new Set(Object.values(AGENT));
3037
3107
  var DEFAULT_AGENT_INSTRUCTION_TARGET_AGENTS = [
3038
3108
  AGENT.CODEX,
@@ -3040,6 +3110,10 @@ var DEFAULT_AGENT_INSTRUCTION_TARGET_AGENTS = [
3040
3110
  ];
3041
3111
  var DEFAULT_AGENT_INSTRUCTION_FILE_PATH = "AGENTS.md";
3042
3112
  var DEFAULT_HARNESS_ENVIRONMENT_CONFIG = {
3113
+ methodology: {
3114
+ source: DEFAULT_METHODOLOGY_SOURCE,
3115
+ version: DEFAULT_METHODOLOGY_VERSION
3116
+ },
3043
3117
  instructions: {
3044
3118
  files: [
3045
3119
  {
@@ -3073,10 +3147,15 @@ var DEFAULT_HARNESS_ENVIRONMENT_CONFIG = {
3073
3147
  }
3074
3148
  };
3075
3149
  var HARNESS_ENVIRONMENT_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
3150
+ HARNESS_ENVIRONMENT_CONFIG_FIELDS.METHODOLOGY,
3076
3151
  HARNESS_ENVIRONMENT_CONFIG_FIELDS.INSTRUCTIONS,
3077
3152
  HARNESS_ENVIRONMENT_CONFIG_FIELDS.AGENTS,
3078
3153
  HARNESS_ENVIRONMENT_CONFIG_FIELDS.PLUGIN_BOOTSTRAP
3079
3154
  ]);
3155
+ var HARNESS_ENVIRONMENT_METHODOLOGY_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
3156
+ HARNESS_ENVIRONMENT_CONFIG_FIELDS.SOURCE,
3157
+ HARNESS_ENVIRONMENT_CONFIG_FIELDS.VERSION
3158
+ ]);
3080
3159
  var HARNESS_ENVIRONMENT_INSTRUCTIONS_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
3081
3160
  HARNESS_ENVIRONMENT_CONFIG_FIELDS.FILES
3082
3161
  ]);
@@ -3141,6 +3220,21 @@ function validateBoolean(path7, value) {
3141
3220
  }
3142
3221
  return { ok: true, value };
3143
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
+ }
3144
3238
  function validateAgent(path7, value) {
3145
3239
  if (typeof value !== "string" || !isAgent(value)) {
3146
3240
  return { ok: false, error: `${path7} must be a registered agent` };
@@ -3522,6 +3616,9 @@ function validate(value) {
3522
3616
  HARNESS_ENVIRONMENT_ALLOWED_FIELDS
3523
3617
  );
3524
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;
3525
3622
  const instructionsRaw = value[HARNESS_ENVIRONMENT_CONFIG_FIELDS.INSTRUCTIONS];
3526
3623
  const instructions = instructionsRaw === void 0 ? { ok: true, value: DEFAULT_HARNESS_ENVIRONMENT_CONFIG.instructions } : validateInstructions(instructionsRaw);
3527
3624
  if (!instructions.ok) return instructions;
@@ -3534,6 +3631,7 @@ function validate(value) {
3534
3631
  return {
3535
3632
  ok: true,
3536
3633
  value: {
3634
+ methodology: methodology.value,
3537
3635
  instructions: instructions.value,
3538
3636
  agents: agents.value,
3539
3637
  pluginBootstrap: pluginBootstrap.value
@@ -3815,59 +3913,6 @@ var fileInclusionConfigDescriptor = {
3815
3913
  validate: validate4
3816
3914
  };
3817
3915
 
3818
- // src/config/source-roots.ts
3819
- var TEST_RELEVANT_SOURCE_ROOT_PREFIX = {
3820
- SOURCE: "src/",
3821
- TESTING: "testing/",
3822
- SCRIPTS: "scripts/",
3823
- ESLINT_RULES: "eslint-rules/"
3824
- };
3825
- var TEST_RELEVANT_SOURCE_ROOT_PREFIXES = [
3826
- TEST_RELEVANT_SOURCE_ROOT_PREFIX.SOURCE,
3827
- TEST_RELEVANT_SOURCE_ROOT_PREFIX.TESTING,
3828
- TEST_RELEVANT_SOURCE_ROOT_PREFIX.SCRIPTS,
3829
- TEST_RELEVANT_SOURCE_ROOT_PREFIX.ESLINT_RULES
3830
- ];
3831
-
3832
- // src/lib/precommit/config.ts
3833
- var PRECOMMIT_SECTION = "precommit";
3834
- var PRECOMMIT_DEFAULTS = {
3835
- sourceDirs: TEST_RELEVANT_SOURCE_ROOT_PREFIXES,
3836
- testPattern: ".test.ts"
3837
- };
3838
- function validate5(value) {
3839
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
3840
- return { ok: false, error: `${PRECOMMIT_SECTION} section must be an object` };
3841
- }
3842
- const candidate = value;
3843
- const sourceDirs = candidate["sourceDirs"] ?? PRECOMMIT_DEFAULTS.sourceDirs;
3844
- if (!Array.isArray(sourceDirs) || !sourceDirs.every((x) => typeof x === "string" && x.length > 0)) {
3845
- return {
3846
- ok: false,
3847
- error: `${PRECOMMIT_SECTION}.sourceDirs must be a non-empty array of non-empty strings`
3848
- };
3849
- }
3850
- const testPattern = candidate["testPattern"] ?? PRECOMMIT_DEFAULTS.testPattern;
3851
- if (typeof testPattern !== "string" || testPattern.length === 0) {
3852
- return {
3853
- ok: false,
3854
- error: `${PRECOMMIT_SECTION}.testPattern must be a non-empty string`
3855
- };
3856
- }
3857
- return {
3858
- ok: true,
3859
- value: {
3860
- sourceDirs,
3861
- testPattern
3862
- }
3863
- };
3864
- }
3865
- var precommitConfigDescriptor = {
3866
- section: PRECOMMIT_SECTION,
3867
- defaults: PRECOMMIT_DEFAULTS,
3868
- validate: validate5
3869
- };
3870
-
3871
3916
  // src/lib/spec-tree/config.ts
3872
3917
  var SPEC_TREE_KIND_CATEGORY_VALUES = {
3873
3918
  NODE: "node",
@@ -4056,7 +4101,7 @@ function buildConfigFromKindNames(kindNames) {
4056
4101
  const entries = kindNames.map((kind) => [kind, KIND_REGISTRY[kind]]);
4057
4102
  return { kinds: Object.fromEntries(entries) };
4058
4103
  }
4059
- function validate6(value) {
4104
+ function validate5(value) {
4060
4105
  if (typeof value !== "object" || value === null) {
4061
4106
  return { ok: false, error: `${SPEC_TREE_SECTION} section must be an object` };
4062
4107
  }
@@ -4155,7 +4200,7 @@ function validateKindDefinitionMap(kindEntries) {
4155
4200
  var specTreeConfigDescriptor = {
4156
4201
  section: SPEC_TREE_SECTION,
4157
4202
  defaults: buildDefaults(),
4158
- validate: validate6
4203
+ validate: validate5
4159
4204
  };
4160
4205
 
4161
4206
  // src/config/primitives/path-filter.ts
@@ -4241,7 +4286,7 @@ function resolveDefaultPassingScope() {
4241
4286
  }
4242
4287
  return result.value;
4243
4288
  }
4244
- function validate7(value) {
4289
+ function validate6(value) {
4245
4290
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
4246
4291
  return { ok: false, error: `${TESTING_SECTION} section must be an object` };
4247
4292
  }
@@ -4265,7 +4310,7 @@ function validate7(value) {
4265
4310
  var testingConfigDescriptor = {
4266
4311
  section: TESTING_SECTION,
4267
4312
  defaults: defaults4,
4268
- validate: validate7
4313
+ validate: validate6
4269
4314
  };
4270
4315
 
4271
4316
  // src/validation/literal/config.ts
@@ -4329,7 +4374,7 @@ var LITERAL_DEFAULTS = {
4329
4374
  function isNonNegativeInteger(value) {
4330
4375
  return typeof value === "number" && Number.isInteger(value) && value >= 0;
4331
4376
  }
4332
- function validate8(value) {
4377
+ function validate7(value) {
4333
4378
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
4334
4379
  return { ok: false, error: `${LITERAL_SECTION} section must be an object` };
4335
4380
  }
@@ -4393,7 +4438,7 @@ function isStringArray(value) {
4393
4438
  var literalConfigDescriptor = {
4394
4439
  section: LITERAL_SECTION,
4395
4440
  defaults: LITERAL_DEFAULTS,
4396
- validate: validate8
4441
+ validate: validate7
4397
4442
  };
4398
4443
 
4399
4444
  // src/validation/config/descriptor.ts
@@ -4486,7 +4531,7 @@ function validateKnip(raw) {
4486
4531
  }
4487
4532
  return { ok: true, value: { enabled: enabledRaw } };
4488
4533
  }
4489
- function validate9(value) {
4534
+ function validate8(value) {
4490
4535
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
4491
4536
  return { ok: false, error: `${VALIDATION_SECTION} section must be an object` };
4492
4537
  }
@@ -4505,7 +4550,7 @@ function validate9(value) {
4505
4550
  var validationConfigDescriptor = {
4506
4551
  section: VALIDATION_SECTION,
4507
4552
  defaults: defaults5,
4508
- validate: validate9
4553
+ validate: validate8
4509
4554
  };
4510
4555
 
4511
4556
  // src/config/registry.ts
@@ -4514,7 +4559,6 @@ var productionRegistry = [
4514
4559
  validationConfigDescriptor,
4515
4560
  testingConfigDescriptor,
4516
4561
  fileInclusionConfigDescriptor,
4517
- precommitConfigDescriptor,
4518
4562
  harnessEnvironmentConfigDescriptor,
4519
4563
  diagnoseConfigDescriptor,
4520
4564
  runtimeConfigDescriptor
@@ -11556,6 +11600,20 @@ function aggregateTestExitCode(invocations, unsupportedSelectionCount = 0) {
11556
11600
  return SUCCESS_EXIT_CODE;
11557
11601
  }
11558
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
+
11559
11617
  // src/domains/test/changed-set-planning.ts
11560
11618
  var PATH_SEPARATOR = "/";
11561
11619
  var MARKDOWN_EXTENSION = ".md";
@@ -19676,6 +19734,7 @@ var UNSEALED_NEXT_ACTIONS = [
19676
19734
  VERIFY_LIFECYCLE_ACTION.FINISH
19677
19735
  ];
19678
19736
  var VERIFY_VERIFICATION_TYPE = {
19737
+ AUDIT: "audit",
19679
19738
  REVIEW: "review"
19680
19739
  };
19681
19740
  var VERIFY_VERIFICATION_TYPES = new Set(Object.values(VERIFY_VERIFICATION_TYPE));
@@ -19686,6 +19745,63 @@ var REVIEW_FINDING_DISPOSITION = {
19686
19745
  BLOCKING: "BLOCKING",
19687
19746
  DEBT: "DEBT"
19688
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
+ };
19689
19805
  var VERIFY_APPEND_EVENT_TYPE = {
19690
19806
  SCOPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.scope`,
19691
19807
  FINDING: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.finding`
@@ -19768,21 +19884,408 @@ function parseAppendPayload(raw) {
19768
19884
  function isJsonRecord(value) {
19769
19885
  return typeof value === "object" && value !== null && !Array.isArray(value);
19770
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
+ }
19771
19925
  function isReviewFindingDisposition(value) {
19772
19926
  return Object.values(REVIEW_FINDING_DISPOSITION).includes(value);
19773
19927
  }
19774
- 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) {
19775
19966
  if (!isJsonRecord(payload)) return void 0;
19776
19967
  const { disposition, summary } = payload;
19777
19968
  if (!isReviewFindingDisposition(disposition)) return void 0;
19778
19969
  if (typeof summary !== "string" || summary.length === 0) return void 0;
19779
19970
  return { disposition, summary };
19780
19971
  }
19781
- var FINDING_VALIDATORS = {
19782
- [VERIFY_VERIFICATION_TYPE.REVIEW]: validateReviewFinding
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
+ };
20007
+ }
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
+ };
20035
+ }
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);
20050
+ return {
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 }
20085
+ }
20086
+ };
20087
+ }
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
+ }
19783
20245
  };
19784
- function findingValidatorFor(verificationType) {
19785
- return FINDING_VALIDATORS[verificationType];
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;
19786
20289
  }
19787
20290
  function findAppendedSequence(events, idempotencyKey, eventType) {
19788
20291
  const match = events.find(
@@ -19805,6 +20308,7 @@ function buildAppendEvent(args) {
19805
20308
  }
19806
20309
  var VERIFY_TERMINAL_EVENT_TYPE = `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.terminal`;
19807
20310
  var VERIFY_TERMINAL_EVENT_FIELD = {
20311
+ TERMINAL_METADATA: "terminalMetadata",
19808
20312
  TERMINAL_STATUS: "terminalStatus"
19809
20313
  };
19810
20314
  var VERIFY_TERMINAL_EVENT_ID_PREFIX = "verify-terminal-";
@@ -19819,7 +20323,8 @@ function buildTerminalEvent(args) {
19819
20323
  time: args.at.toISOString(),
19820
20324
  attempt: VERIFY_APPEND_ATTEMPT,
19821
20325
  data: {
19822
- [VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_STATUS]: args.terminalStatus
20326
+ [VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_STATUS]: args.terminalStatus,
20327
+ ...args.terminalMetadata === void 0 ? {} : { [VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_METADATA]: args.terminalMetadata }
19823
20328
  }
19824
20329
  };
19825
20330
  }
@@ -19832,11 +20337,23 @@ function terminalStatusOf(event) {
19832
20337
  const status = event.data[VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_STATUS];
19833
20338
  return typeof status === "string" ? status : void 0;
19834
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
+ }
19835
20344
  function countVerifyFindings(events) {
19836
20345
  return events.filter(
19837
20346
  (event) => event.type === VERIFY_APPEND_EVENT_TYPE.FINDING
19838
20347
  ).length;
19839
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
+ }
19840
20357
  function lastSequenceOf(events) {
19841
20358
  return events.reduce(
19842
20359
  (max, event) => event.seq > max ? event.seq : max,
@@ -19846,10 +20363,12 @@ function lastSequenceOf(events) {
19846
20363
  function projectVerifyRun(events) {
19847
20364
  const terminal = findTerminalEvent(events);
19848
20365
  const terminalStatus = terminalStatusOf(terminal);
20366
+ const terminalMetadata = terminalMetadataOf(terminal);
19849
20367
  const sealed = terminal !== void 0;
19850
20368
  return {
19851
20369
  sealed,
19852
20370
  ...terminalStatus === void 0 ? {} : { terminalStatus },
20371
+ ...terminalMetadata === void 0 ? {} : { terminalMetadata },
19853
20372
  findingCount: countVerifyFindings(events),
19854
20373
  lastSequence: lastSequenceOf(events),
19855
20374
  nextActions: sealed ? [] : UNSEALED_NEXT_ACTIONS
@@ -19877,11 +20396,14 @@ var VERIFY_CLI_ERROR = {
19877
20396
  PAYLOAD_READ_FAILED: "spx verification run could not read the evidence payload",
19878
20397
  PAYLOAD_INVALID: "spx verification run evidence payload is not valid JSON",
19879
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",
19880
20400
  FINDING_INVALID: "spx verification run finding add payload failed verification-type validation",
19881
20401
  UNSUPPORTED_VERIFICATION_TYPE: "spx verification run verification type is not registered",
19882
20402
  APPEND_FAILED: "spx verification run could not append the evidence event",
19883
20403
  TERMINAL_STATUS_REQUIRED: "spx verification run finish requires --terminal-status <status>",
19884
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",
19885
20407
  FINISH_FAILED: "spx verification run could not record terminal completion",
19886
20408
  SEAL_FAILED: "spx verification run could not seal the run journal",
19887
20409
  STATUS_FAILED: "spx verification run could not read the run status",
@@ -20271,12 +20793,18 @@ function appendRunSelectorMismatchDiagnostic(options, backendIdentity, namespace
20271
20793
  searchedTarget
20272
20794
  });
20273
20795
  }
20274
- function validateAppendFinding(verb, verificationType, payload) {
20275
- if (verb !== VERIFY_VERB.APPEND_FINDING) return void 0;
20276
- const validator = findingValidatorFor(verificationType);
20277
- if (validator === void 0) return VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE;
20278
- if (validator(payload) === void 0) return VERIFY_CLI_ERROR.FINDING_INVALID;
20279
- return void 0;
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)) };
20280
20808
  }
20281
20809
  function appendEventType(verb) {
20282
20810
  return verb === VERIFY_VERB.APPEND_FINDING ? VERIFY_APPEND_EVENT_TYPE.FINDING : VERIFY_APPEND_EVENT_TYPE.SCOPE;
@@ -20299,12 +20827,12 @@ async function verifyAppend(options, deps, verb) {
20299
20827
  }
20300
20828
  const parsed = parseAppendPayload(rawPayload);
20301
20829
  if (parsed === void 0) return errorResult3(VERIFY_CLI_ERROR.PAYLOAD_INVALID);
20302
- const findingError = validateAppendFinding(verb, options.verificationType, parsed);
20303
- if (findingError !== void 0) return errorResult3(findingError);
20830
+ const evidence = validateAppendEvidence(verb, options.verificationType, parsed, existingEvents);
20831
+ if (!evidence.ok) return errorResult3(evidence.error);
20304
20832
  const event = buildAppendEvent({
20305
20833
  eventType,
20306
20834
  idempotencyKey: options.idempotencyKey,
20307
- payload: parsed,
20835
+ payload: evidence.value,
20308
20836
  at: deps.now?.() ?? /* @__PURE__ */ new Date()
20309
20837
  });
20310
20838
  const appended = await journalAppendCommand(journalScope, event, binding, forwardDeps(deps));
@@ -20422,6 +20950,7 @@ function verifyFinishReport(runToken, projection) {
20422
20950
  return {
20423
20951
  runToken,
20424
20952
  ...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
20953
+ ...projection.terminalMetadata === void 0 ? {} : { terminalMetadata: projection.terminalMetadata },
20425
20954
  sealed: projection.sealed,
20426
20955
  findingCount: projection.findingCount,
20427
20956
  lastSequence: projection.lastSequence
@@ -20446,6 +20975,31 @@ function finishReadFailure(run, options, error) {
20446
20975
  }
20447
20976
  return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${error}`);
20448
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
+ }
20449
21003
  async function finishProjectionResult(run, deps) {
20450
21004
  const events = await readRunJournalEvents(run.journalScope, deps);
20451
21005
  if (!events.ok) return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${events.error}`);
@@ -20475,11 +21029,21 @@ async function verifyFinishCommand(options, deps) {
20475
21029
  if (inputRecord.value === void 0) {
20476
21030
  return errorResult3(existingRunNotFound(run.value, options));
20477
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);
20478
21041
  const binding = deps.journalBinding;
20479
21042
  if (binding === void 0) return errorResult3(VERIFY_CLI_ERROR.FINISH_FAILED);
20480
21043
  const event = buildTerminalEvent({
20481
21044
  runToken: run.value.runToken,
20482
21045
  terminalStatus: options.terminalStatus,
21046
+ ...terminalMetadata.value === void 0 ? {} : { terminalMetadata: terminalMetadata.value },
20483
21047
  at: deps.now?.() ?? /* @__PURE__ */ new Date()
20484
21048
  });
20485
21049
  const appended = await journalAppendCommand(run.value.journalScope, event, binding, forwardDeps(deps));
@@ -20513,6 +21077,7 @@ async function verifyStatusCommand(options, deps) {
20513
21077
  sealed: projection.sealed,
20514
21078
  lastSequence: projection.lastSequence,
20515
21079
  ...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
21080
+ ...projection.terminalMetadata === void 0 ? {} : { terminalMetadata: projection.terminalMetadata },
20516
21081
  findingCount: projection.findingCount,
20517
21082
  nextActions: projection.nextActions
20518
21083
  };
@@ -20539,6 +21104,7 @@ async function verifyRenderCommand(options, deps) {
20539
21104
  findingCount: projection.findingCount,
20540
21105
  sealed: projection.sealed,
20541
21106
  ...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
21107
+ ...projection.terminalMetadata === void 0 ? {} : { terminalMetadata: projection.terminalMetadata },
20542
21108
  events: events.value
20543
21109
  };
20544
21110
  return okResult3(JSON.stringify(report2));
@@ -20576,6 +21142,7 @@ var VERIFY_CLI = {
20576
21142
  payloadOptionDescription: "Evidence payload source; stdin or a file path",
20577
21143
  idempotencyKeyOption: "--idempotency-key <key>",
20578
21144
  idempotencyKeyOptionDescription: "Caller-supplied idempotency key for the evidence add",
21145
+ terminalMetadataOption: "--terminal-metadata <payload-source>",
20579
21146
  terminalStatusOption: "--terminal-status <status>"
20580
21147
  };
20581
21148
  var CLI_SOURCE_ENCODING = "utf8";
@@ -20629,7 +21196,7 @@ function registerVerifyCommands(program, invocation, handlers = DEFAULT_VERIFY_C
20629
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) => {
20630
21197
  reportCliResult(await handlers.appendFinding(options, deps()), invocation.io);
20631
21198
  });
20632
- 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").action(async (options) => {
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) => {
20633
21200
  reportCliResult(await handlers.finish(options, deps()), invocation.io);
20634
21201
  });
20635
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) => {