@riddledc/riddle-proof 0.7.218 → 0.7.220

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.cjs +235 -4
  2. package/dist/cli.js +235 -4
  3. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -16332,6 +16332,92 @@ function extractRiddleProofProfileResult(input) {
16332
16332
 
16333
16333
  // src/cli.ts
16334
16334
  var RIDDLE_PROFILE_BALANCE_PREFLIGHT_MIN_SECONDS_PER_JOB = 30;
16335
+ var KNOWN_CLI_OPTIONS = /* @__PURE__ */ new Set([
16336
+ "agent",
16337
+ "apiBaseUrl",
16338
+ "apiKey",
16339
+ "apiKeyFile",
16340
+ "artifact",
16341
+ "attempts",
16342
+ "balancePreflight",
16343
+ "baseUrl",
16344
+ "candidateJson",
16345
+ "candidatesJson",
16346
+ "checkpointMode",
16347
+ "checkpointVisibility",
16348
+ "codexCommand",
16349
+ "codexFullAuto",
16350
+ "codexHome",
16351
+ "codexModel",
16352
+ "codexSandbox",
16353
+ "codexTimeoutMs",
16354
+ "command",
16355
+ "continueWithStage",
16356
+ "createdAt",
16357
+ "decision",
16358
+ "defaultReviewer",
16359
+ "defaultShipMode",
16360
+ "exclude",
16361
+ "format",
16362
+ "framework",
16363
+ "help",
16364
+ "image",
16365
+ "input",
16366
+ "inputDir",
16367
+ "inputFile",
16368
+ "inputFiles",
16369
+ "inputs",
16370
+ "intervalMs",
16371
+ "job",
16372
+ "jobId",
16373
+ "maxIterations",
16374
+ "navigationTimeout",
16375
+ "output",
16376
+ "outputDir",
16377
+ "path",
16378
+ "payloadJson",
16379
+ "pollAttempts",
16380
+ "pollIntervalMs",
16381
+ "port",
16382
+ "profile",
16383
+ "progressEveryMs",
16384
+ "quiet",
16385
+ "readinessPath",
16386
+ "readinessTimeout",
16387
+ "reasonsJson",
16388
+ "requestJson",
16389
+ "requiredJson",
16390
+ "responseJson",
16391
+ "resultFormat",
16392
+ "resultsDir",
16393
+ "riddleEngineModuleUrl",
16394
+ "riddleProofDir",
16395
+ "route",
16396
+ "runDir",
16397
+ "runner",
16398
+ "scriptFile",
16399
+ "sourceKind",
16400
+ "splitViewports",
16401
+ "stateDir",
16402
+ "statePath",
16403
+ "strict",
16404
+ "submitRetries",
16405
+ "submitTimeoutMs",
16406
+ "summary",
16407
+ "sync",
16408
+ "timeout",
16409
+ "url",
16410
+ "unsubmittedJobRetries",
16411
+ "unsubmittedJobTimeoutMs",
16412
+ "unsubmittedRetries",
16413
+ "unsubmittedTimeoutMs",
16414
+ "viewport",
16415
+ "viewportName",
16416
+ "viewportNames",
16417
+ "viewports",
16418
+ "wait",
16419
+ "waitForSelector"
16420
+ ]);
16335
16421
  function usage() {
16336
16422
  return [
16337
16423
  "Usage:",
@@ -16340,9 +16426,9 @@ function usage() {
16340
16426
  " riddle-proof-loop respond --state-path <path> --response-json <file|json|->",
16341
16427
  " riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
16342
16428
  " riddle-proof-loop status --state-path <path>",
16343
- " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--viewport-name <name[,name...]>] [--strict true|false; default false] [--split-viewports true|false; default false] [--balance-preflight true|false; default true] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json] [--quiet]",
16344
- " riddle-proof-loop run-profile aggregate --profile <file|json|-> --url <base-url> --input-dir <dir>|--inputs <path[,path...]> [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
16345
- " riddle-proof-loop run-profile recover --profile <file|json|-> --url <base-url> --job <job-id> [--viewport-name <name[,name...]>] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
16429
+ " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--base-url <base-url>] [--runner riddle] [--viewport-name <name[,name...]>] [--strict true|false; default false] [--split-viewports true|false; default false] [--balance-preflight true|false; default true] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json] [--quiet]",
16430
+ " riddle-proof-loop run-profile aggregate --profile <file|json|-> --url <base-url> [--base-url <base-url>] --input-dir <dir>|--inputs <path[,path...]> [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
16431
+ " riddle-proof-loop run-profile recover --profile <file|json|-> --url <base-url> [--base-url <base-url>] --job <job-id> [--viewport-name <name[,name...]>] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
16346
16432
  " riddle-proof-loop profile-body-assertions --artifact <file|url|-> --candidates-json <file|json|-> [--required-json <file|json|->] [--format json|body-contains]",
16347
16433
  " riddle-proof-loop profile-http-status-preflight --profile <file|json|-> --url <base-url> [--format json|summary]",
16348
16434
  " riddle-proof-loop riddle-preview-deploy <build-dir> <label> [--framework spa|static]",
@@ -16382,6 +16468,15 @@ function parseArgs(argv) {
16382
16468
  }
16383
16469
  return { positional, options };
16384
16470
  }
16471
+ function optionKeyToFlagName(key) {
16472
+ return key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
16473
+ }
16474
+ function validateCliOptions(options) {
16475
+ const unknown = Object.keys(options).filter((key) => !KNOWN_CLI_OPTIONS.has(key));
16476
+ if (!unknown.length) return;
16477
+ const flags = unknown.map((key) => `--${optionKeyToFlagName(key)}`).join(", ");
16478
+ throw new Error(`Unknown option${unknown.length === 1 ? "" : "s"}: ${flags}. Run riddle-proof-loop help for usage.`);
16479
+ }
16385
16480
  function optionString(options, key) {
16386
16481
  const value = options[key];
16387
16482
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
@@ -16703,7 +16798,7 @@ function parseProfileViewports(value) {
16703
16798
  function normalizeProfileForCli(options) {
16704
16799
  const rawProfile = readJsonValue(optionString(options, "profile"), "--profile");
16705
16800
  return normalizeRiddleProofProfile(rawProfile, {
16706
- url: optionString(options, "url"),
16801
+ url: optionString(options, "url") ?? optionString(options, "baseUrl"),
16707
16802
  route: optionString(options, "route"),
16708
16803
  viewports: parseProfileViewports(optionString(options, "viewports") || optionString(options, "viewport"))
16709
16804
  });
@@ -17380,6 +17475,137 @@ function profileHasGeneratedOutputReceipt(receipts) {
17380
17475
  }
17381
17476
  return outputReady && outputChanged;
17382
17477
  }
17478
+ function profileSemanticReceiptPassed(receipt) {
17479
+ if (receipt.ok === false) return false;
17480
+ return setupReturnSummaryValue(receipt, ["ok", "success", "passed", "completed", "valid"]) === true;
17481
+ }
17482
+ function profileSemanticArrayEvidence(value) {
17483
+ if (Array.isArray(value)) return value.length > 0;
17484
+ const text = cliString(value);
17485
+ return Boolean(text && text.trim());
17486
+ }
17487
+ function profileSemanticTruthyField(receipt, names) {
17488
+ return names.some((name) => setupReturnSummaryValue(receipt, [name]) === true);
17489
+ }
17490
+ function profileHasBoardEvidence(receipt) {
17491
+ return [
17492
+ "board",
17493
+ "beforeBoard",
17494
+ "afterBoard",
17495
+ "cells",
17496
+ "grid",
17497
+ "state"
17498
+ ].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
17499
+ }
17500
+ function profileHasTurnEvidence(receipt) {
17501
+ return [
17502
+ "activeX",
17503
+ "activeO",
17504
+ "turn",
17505
+ "currentTurn",
17506
+ "nextTurn",
17507
+ "currentPlayer",
17508
+ "nextPlayer",
17509
+ "isXNext"
17510
+ ].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
17511
+ }
17512
+ function profileSemanticInvalidStateReason(receipts, text) {
17513
+ const asksInvalidOrBlocked = text.includes("invalid") || text.includes("blocked") || text.includes("occupied") || text.includes("replay") || text.includes("ignored") || text.includes("reject") || text.includes("same board") || text.includes("unchanged");
17514
+ if (!asksInvalidOrBlocked) return void 0;
17515
+ const asksTurn = text.includes("turn") || text.includes("player");
17516
+ for (const receipt of receipts) {
17517
+ if (!profileSemanticReceiptPassed(receipt)) continue;
17518
+ const unchanged = profileSemanticTruthyField(receipt, [
17519
+ "sameBoard",
17520
+ "same_board",
17521
+ "boardUnchanged",
17522
+ "stateUnchanged",
17523
+ "unchanged",
17524
+ "noMutation",
17525
+ "no_mutation"
17526
+ ]);
17527
+ const blocked = profileSemanticTruthyField(receipt, [
17528
+ "blocked",
17529
+ "invalid",
17530
+ "rejected",
17531
+ "ignored",
17532
+ "prevented"
17533
+ ]);
17534
+ if (!(unchanged || blocked)) continue;
17535
+ if (!profileHasBoardEvidence(receipt)) continue;
17536
+ if (asksTurn && !profileHasTurnEvidence(receipt)) continue;
17537
+ const parts = [
17538
+ unchanged ? "unchanged=true" : "",
17539
+ blocked ? "blocked=true" : "",
17540
+ profileHasTurnEvidence(receipt) ? "turn evidence present" : ""
17541
+ ].filter(Boolean);
17542
+ return `semantic invalid-state receipt present${parts.length ? `: ${parts.join(", ")}` : ""}`;
17543
+ }
17544
+ return void 0;
17545
+ }
17546
+ function profileSemanticTerminalLockReason(receipts, text) {
17547
+ const asksLock = text.includes("lock") || text.includes("cannot mutate") || text.includes("can not mutate") || text.includes("can't mutate") || text.includes("cannot change") || text.includes("unchanged after") || text.includes("post-winner") && text.includes("click") || text.includes("post winner") && text.includes("click");
17548
+ if (!asksLock) return void 0;
17549
+ for (const receipt of receipts) {
17550
+ if (!profileSemanticReceiptPassed(receipt)) continue;
17551
+ const unchanged = profileSemanticTruthyField(receipt, [
17552
+ "sameBoard",
17553
+ "same_board",
17554
+ "boardUnchanged",
17555
+ "stateUnchanged",
17556
+ "unchanged",
17557
+ "noMutation",
17558
+ "no_mutation",
17559
+ "locked"
17560
+ ]);
17561
+ if (!unchanged) continue;
17562
+ const hasTerminal = profileSemanticTruthyField(receipt, ["hasWinner", "winner", "won", "gameWon", "terminal", "locked"]) || profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv", "winnerText", "terminalText", "statusText"])));
17563
+ if (!hasTerminal) continue;
17564
+ return "semantic terminal-lock receipt present: unchanged=true";
17565
+ }
17566
+ return void 0;
17567
+ }
17568
+ function profileSemanticWinnerReason(receipts, text) {
17569
+ const asksWinner = text.includes("winner") || text.includes("win-cell") || text.includes("winning") || /\bwin\b/.test(text);
17570
+ if (!asksWinner) return void 0;
17571
+ const asksCounts = text.includes("count");
17572
+ const asksWinCells = text.includes("win-cell") || text.includes("winning") || text.includes("inventory") || text.includes("top-row");
17573
+ const asksPlayAgain = text.includes("play again") || text.includes("play-again") || text.includes("playagain");
17574
+ for (const receipt of receipts) {
17575
+ if (!profileSemanticReceiptPassed(receipt)) continue;
17576
+ const winnerText = (cliString(setupReturnSummaryValue(receipt, ["winnerText", "terminalText", "statusText"])) || "").toLowerCase();
17577
+ const hasWinner = profileSemanticTruthyField(receipt, ["hasWinner", "winner", "won", "gameWon"]) || winnerText.includes("win") || profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv"])));
17578
+ if (!hasWinner) continue;
17579
+ const hasCounts = [
17580
+ "xCount",
17581
+ "oCount",
17582
+ "count",
17583
+ "filledCount",
17584
+ "winnerCount",
17585
+ "score"
17586
+ ].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
17587
+ const hasWinCells = profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv"])));
17588
+ const hasPlayAgain = profileSemanticTruthyField(receipt, [
17589
+ "playAgainVisible",
17590
+ "play_again_visible",
17591
+ "restartVisible",
17592
+ "resetVisible"
17593
+ ]);
17594
+ if (asksCounts && !hasCounts) continue;
17595
+ if (asksWinCells && !hasWinCells) continue;
17596
+ if (asksPlayAgain && !hasPlayAgain) continue;
17597
+ const parts = [
17598
+ hasCounts ? "counts present" : "",
17599
+ hasWinCells ? "win cells present" : "",
17600
+ hasPlayAgain ? "play-again visible" : ""
17601
+ ].filter(Boolean);
17602
+ return `semantic winner receipt present${parts.length ? `: ${parts.join(", ")}` : ""}`;
17603
+ }
17604
+ return void 0;
17605
+ }
17606
+ function profileSemanticStateReceiptReason(receipts, text) {
17607
+ return profileSemanticTerminalLockReason(receipts, text) || profileSemanticInvalidStateReason(receipts, text) || profileSemanticWinnerReason(receipts, text);
17608
+ }
17383
17609
  function profilePackReceiptStatus(result, metadata, receipt) {
17384
17610
  const text = receipt.toLowerCase();
17385
17611
  const setupSummary = profileSetupSummaryRecord(result);
@@ -17838,6 +18064,10 @@ function profilePackReceiptStatus(result, metadata, receipt) {
17838
18064
  if (text.includes("measured") || text.includes("state-change") || text.includes("pixel delta") || text.includes("movement receipt") || text.includes("canvas hash")) {
17839
18065
  return profileReceiptSignalStatus(hasMeasuredStateChange, "measured-change evidence present", "measured-change evidence missing");
17840
18066
  }
18067
+ const semanticStateReason = profileSemanticStateReceiptReason(valueReceipts, text);
18068
+ if (semanticStateReason) {
18069
+ return { status: "present", reason: semanticStateReason };
18070
+ }
17841
18071
  return { status: "manual", reason: "semantic receipt requires audit review" };
17842
18072
  }
17843
18073
  function profilePackMetadataMarkdown(result) {
@@ -19955,6 +20185,7 @@ async function main() {
19955
20185
  `);
19956
20186
  return;
19957
20187
  }
20188
+ validateCliOptions(options);
19958
20189
  if (command === "doctor") {
19959
20190
  const subject = positional[1];
19960
20191
  if (!isLocalAgentMode(subject)) throw new Error("Only `doctor local` is supported.");
package/dist/cli.js CHANGED
@@ -41,6 +41,92 @@ import "./chunk-VY4Y5U57.js";
41
41
  import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
42
42
  import path from "path";
43
43
  var RIDDLE_PROFILE_BALANCE_PREFLIGHT_MIN_SECONDS_PER_JOB = 30;
44
+ var KNOWN_CLI_OPTIONS = /* @__PURE__ */ new Set([
45
+ "agent",
46
+ "apiBaseUrl",
47
+ "apiKey",
48
+ "apiKeyFile",
49
+ "artifact",
50
+ "attempts",
51
+ "balancePreflight",
52
+ "baseUrl",
53
+ "candidateJson",
54
+ "candidatesJson",
55
+ "checkpointMode",
56
+ "checkpointVisibility",
57
+ "codexCommand",
58
+ "codexFullAuto",
59
+ "codexHome",
60
+ "codexModel",
61
+ "codexSandbox",
62
+ "codexTimeoutMs",
63
+ "command",
64
+ "continueWithStage",
65
+ "createdAt",
66
+ "decision",
67
+ "defaultReviewer",
68
+ "defaultShipMode",
69
+ "exclude",
70
+ "format",
71
+ "framework",
72
+ "help",
73
+ "image",
74
+ "input",
75
+ "inputDir",
76
+ "inputFile",
77
+ "inputFiles",
78
+ "inputs",
79
+ "intervalMs",
80
+ "job",
81
+ "jobId",
82
+ "maxIterations",
83
+ "navigationTimeout",
84
+ "output",
85
+ "outputDir",
86
+ "path",
87
+ "payloadJson",
88
+ "pollAttempts",
89
+ "pollIntervalMs",
90
+ "port",
91
+ "profile",
92
+ "progressEveryMs",
93
+ "quiet",
94
+ "readinessPath",
95
+ "readinessTimeout",
96
+ "reasonsJson",
97
+ "requestJson",
98
+ "requiredJson",
99
+ "responseJson",
100
+ "resultFormat",
101
+ "resultsDir",
102
+ "riddleEngineModuleUrl",
103
+ "riddleProofDir",
104
+ "route",
105
+ "runDir",
106
+ "runner",
107
+ "scriptFile",
108
+ "sourceKind",
109
+ "splitViewports",
110
+ "stateDir",
111
+ "statePath",
112
+ "strict",
113
+ "submitRetries",
114
+ "submitTimeoutMs",
115
+ "summary",
116
+ "sync",
117
+ "timeout",
118
+ "url",
119
+ "unsubmittedJobRetries",
120
+ "unsubmittedJobTimeoutMs",
121
+ "unsubmittedRetries",
122
+ "unsubmittedTimeoutMs",
123
+ "viewport",
124
+ "viewportName",
125
+ "viewportNames",
126
+ "viewports",
127
+ "wait",
128
+ "waitForSelector"
129
+ ]);
44
130
  function usage() {
45
131
  return [
46
132
  "Usage:",
@@ -49,9 +135,9 @@ function usage() {
49
135
  " riddle-proof-loop respond --state-path <path> --response-json <file|json|->",
50
136
  " riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
51
137
  " riddle-proof-loop status --state-path <path>",
52
- " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--runner riddle] [--viewport-name <name[,name...]>] [--strict true|false; default false] [--split-viewports true|false; default false] [--balance-preflight true|false; default true] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json] [--quiet]",
53
- " riddle-proof-loop run-profile aggregate --profile <file|json|-> --url <base-url> --input-dir <dir>|--inputs <path[,path...]> [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
54
- " riddle-proof-loop run-profile recover --profile <file|json|-> --url <base-url> --job <job-id> [--viewport-name <name[,name...]>] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
138
+ " riddle-proof-loop run-profile --profile <file|json|-> --url <base-url> [--base-url <base-url>] [--runner riddle] [--viewport-name <name[,name...]>] [--strict true|false; default false] [--split-viewports true|false; default false] [--balance-preflight true|false; default true] [--poll-attempts n] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json] [--quiet]",
139
+ " riddle-proof-loop run-profile aggregate --profile <file|json|-> --url <base-url> [--base-url <base-url>] --input-dir <dir>|--inputs <path[,path...]> [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
140
+ " riddle-proof-loop run-profile recover --profile <file|json|-> --url <base-url> [--base-url <base-url>] --job <job-id> [--viewport-name <name[,name...]>] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
55
141
  " riddle-proof-loop profile-body-assertions --artifact <file|url|-> --candidates-json <file|json|-> [--required-json <file|json|->] [--format json|body-contains]",
56
142
  " riddle-proof-loop profile-http-status-preflight --profile <file|json|-> --url <base-url> [--format json|summary]",
57
143
  " riddle-proof-loop riddle-preview-deploy <build-dir> <label> [--framework spa|static]",
@@ -91,6 +177,15 @@ function parseArgs(argv) {
91
177
  }
92
178
  return { positional, options };
93
179
  }
180
+ function optionKeyToFlagName(key) {
181
+ return key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
182
+ }
183
+ function validateCliOptions(options) {
184
+ const unknown = Object.keys(options).filter((key) => !KNOWN_CLI_OPTIONS.has(key));
185
+ if (!unknown.length) return;
186
+ const flags = unknown.map((key) => `--${optionKeyToFlagName(key)}`).join(", ");
187
+ throw new Error(`Unknown option${unknown.length === 1 ? "" : "s"}: ${flags}. Run riddle-proof-loop help for usage.`);
188
+ }
94
189
  function optionString(options, key) {
95
190
  const value = options[key];
96
191
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
@@ -412,7 +507,7 @@ function parseProfileViewports(value) {
412
507
  function normalizeProfileForCli(options) {
413
508
  const rawProfile = readJsonValue(optionString(options, "profile"), "--profile");
414
509
  return normalizeRiddleProofProfile(rawProfile, {
415
- url: optionString(options, "url"),
510
+ url: optionString(options, "url") ?? optionString(options, "baseUrl"),
416
511
  route: optionString(options, "route"),
417
512
  viewports: parseProfileViewports(optionString(options, "viewports") || optionString(options, "viewport"))
418
513
  });
@@ -1089,6 +1184,137 @@ function profileHasGeneratedOutputReceipt(receipts) {
1089
1184
  }
1090
1185
  return outputReady && outputChanged;
1091
1186
  }
1187
+ function profileSemanticReceiptPassed(receipt) {
1188
+ if (receipt.ok === false) return false;
1189
+ return setupReturnSummaryValue(receipt, ["ok", "success", "passed", "completed", "valid"]) === true;
1190
+ }
1191
+ function profileSemanticArrayEvidence(value) {
1192
+ if (Array.isArray(value)) return value.length > 0;
1193
+ const text = cliString(value);
1194
+ return Boolean(text && text.trim());
1195
+ }
1196
+ function profileSemanticTruthyField(receipt, names) {
1197
+ return names.some((name) => setupReturnSummaryValue(receipt, [name]) === true);
1198
+ }
1199
+ function profileHasBoardEvidence(receipt) {
1200
+ return [
1201
+ "board",
1202
+ "beforeBoard",
1203
+ "afterBoard",
1204
+ "cells",
1205
+ "grid",
1206
+ "state"
1207
+ ].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
1208
+ }
1209
+ function profileHasTurnEvidence(receipt) {
1210
+ return [
1211
+ "activeX",
1212
+ "activeO",
1213
+ "turn",
1214
+ "currentTurn",
1215
+ "nextTurn",
1216
+ "currentPlayer",
1217
+ "nextPlayer",
1218
+ "isXNext"
1219
+ ].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
1220
+ }
1221
+ function profileSemanticInvalidStateReason(receipts, text) {
1222
+ const asksInvalidOrBlocked = text.includes("invalid") || text.includes("blocked") || text.includes("occupied") || text.includes("replay") || text.includes("ignored") || text.includes("reject") || text.includes("same board") || text.includes("unchanged");
1223
+ if (!asksInvalidOrBlocked) return void 0;
1224
+ const asksTurn = text.includes("turn") || text.includes("player");
1225
+ for (const receipt of receipts) {
1226
+ if (!profileSemanticReceiptPassed(receipt)) continue;
1227
+ const unchanged = profileSemanticTruthyField(receipt, [
1228
+ "sameBoard",
1229
+ "same_board",
1230
+ "boardUnchanged",
1231
+ "stateUnchanged",
1232
+ "unchanged",
1233
+ "noMutation",
1234
+ "no_mutation"
1235
+ ]);
1236
+ const blocked = profileSemanticTruthyField(receipt, [
1237
+ "blocked",
1238
+ "invalid",
1239
+ "rejected",
1240
+ "ignored",
1241
+ "prevented"
1242
+ ]);
1243
+ if (!(unchanged || blocked)) continue;
1244
+ if (!profileHasBoardEvidence(receipt)) continue;
1245
+ if (asksTurn && !profileHasTurnEvidence(receipt)) continue;
1246
+ const parts = [
1247
+ unchanged ? "unchanged=true" : "",
1248
+ blocked ? "blocked=true" : "",
1249
+ profileHasTurnEvidence(receipt) ? "turn evidence present" : ""
1250
+ ].filter(Boolean);
1251
+ return `semantic invalid-state receipt present${parts.length ? `: ${parts.join(", ")}` : ""}`;
1252
+ }
1253
+ return void 0;
1254
+ }
1255
+ function profileSemanticTerminalLockReason(receipts, text) {
1256
+ const asksLock = text.includes("lock") || text.includes("cannot mutate") || text.includes("can not mutate") || text.includes("can't mutate") || text.includes("cannot change") || text.includes("unchanged after") || text.includes("post-winner") && text.includes("click") || text.includes("post winner") && text.includes("click");
1257
+ if (!asksLock) return void 0;
1258
+ for (const receipt of receipts) {
1259
+ if (!profileSemanticReceiptPassed(receipt)) continue;
1260
+ const unchanged = profileSemanticTruthyField(receipt, [
1261
+ "sameBoard",
1262
+ "same_board",
1263
+ "boardUnchanged",
1264
+ "stateUnchanged",
1265
+ "unchanged",
1266
+ "noMutation",
1267
+ "no_mutation",
1268
+ "locked"
1269
+ ]);
1270
+ if (!unchanged) continue;
1271
+ const hasTerminal = profileSemanticTruthyField(receipt, ["hasWinner", "winner", "won", "gameWon", "terminal", "locked"]) || profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv", "winnerText", "terminalText", "statusText"])));
1272
+ if (!hasTerminal) continue;
1273
+ return "semantic terminal-lock receipt present: unchanged=true";
1274
+ }
1275
+ return void 0;
1276
+ }
1277
+ function profileSemanticWinnerReason(receipts, text) {
1278
+ const asksWinner = text.includes("winner") || text.includes("win-cell") || text.includes("winning") || /\bwin\b/.test(text);
1279
+ if (!asksWinner) return void 0;
1280
+ const asksCounts = text.includes("count");
1281
+ const asksWinCells = text.includes("win-cell") || text.includes("winning") || text.includes("inventory") || text.includes("top-row");
1282
+ const asksPlayAgain = text.includes("play again") || text.includes("play-again") || text.includes("playagain");
1283
+ for (const receipt of receipts) {
1284
+ if (!profileSemanticReceiptPassed(receipt)) continue;
1285
+ const winnerText = (cliString(setupReturnSummaryValue(receipt, ["winnerText", "terminalText", "statusText"])) || "").toLowerCase();
1286
+ const hasWinner = profileSemanticTruthyField(receipt, ["hasWinner", "winner", "won", "gameWon"]) || winnerText.includes("win") || profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv"])));
1287
+ if (!hasWinner) continue;
1288
+ const hasCounts = [
1289
+ "xCount",
1290
+ "oCount",
1291
+ "count",
1292
+ "filledCount",
1293
+ "winnerCount",
1294
+ "score"
1295
+ ].some((name) => setupReturnSummaryValue(receipt, [name]) !== void 0);
1296
+ const hasWinCells = profileSemanticArrayEvidence(setupReturnSummaryValue(receipt, ["winCells", "winningCells", "winningLine"])) || Boolean(cliString(setupReturnSummaryValue(receipt, ["winCellsCsv"])));
1297
+ const hasPlayAgain = profileSemanticTruthyField(receipt, [
1298
+ "playAgainVisible",
1299
+ "play_again_visible",
1300
+ "restartVisible",
1301
+ "resetVisible"
1302
+ ]);
1303
+ if (asksCounts && !hasCounts) continue;
1304
+ if (asksWinCells && !hasWinCells) continue;
1305
+ if (asksPlayAgain && !hasPlayAgain) continue;
1306
+ const parts = [
1307
+ hasCounts ? "counts present" : "",
1308
+ hasWinCells ? "win cells present" : "",
1309
+ hasPlayAgain ? "play-again visible" : ""
1310
+ ].filter(Boolean);
1311
+ return `semantic winner receipt present${parts.length ? `: ${parts.join(", ")}` : ""}`;
1312
+ }
1313
+ return void 0;
1314
+ }
1315
+ function profileSemanticStateReceiptReason(receipts, text) {
1316
+ return profileSemanticTerminalLockReason(receipts, text) || profileSemanticInvalidStateReason(receipts, text) || profileSemanticWinnerReason(receipts, text);
1317
+ }
1092
1318
  function profilePackReceiptStatus(result, metadata, receipt) {
1093
1319
  const text = receipt.toLowerCase();
1094
1320
  const setupSummary = profileSetupSummaryRecord(result);
@@ -1547,6 +1773,10 @@ function profilePackReceiptStatus(result, metadata, receipt) {
1547
1773
  if (text.includes("measured") || text.includes("state-change") || text.includes("pixel delta") || text.includes("movement receipt") || text.includes("canvas hash")) {
1548
1774
  return profileReceiptSignalStatus(hasMeasuredStateChange, "measured-change evidence present", "measured-change evidence missing");
1549
1775
  }
1776
+ const semanticStateReason = profileSemanticStateReceiptReason(valueReceipts, text);
1777
+ if (semanticStateReason) {
1778
+ return { status: "present", reason: semanticStateReason };
1779
+ }
1550
1780
  return { status: "manual", reason: "semantic receipt requires audit review" };
1551
1781
  }
1552
1782
  function profilePackMetadataMarkdown(result) {
@@ -3664,6 +3894,7 @@ async function main() {
3664
3894
  `);
3665
3895
  return;
3666
3896
  }
3897
+ validateCliOptions(options);
3667
3898
  if (command === "doctor") {
3668
3899
  const subject = positional[1];
3669
3900
  if (!isLocalAgentMode(subject)) throw new Error("Only `doctor local` is supported.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.218",
3
+ "version": "0.7.220",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",