@riddledc/riddle-proof 0.8.40 → 0.8.42

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.
@@ -1,5 +1,5 @@
1
1
  export { b as runner } from '../runner-4LJ5z0D-.cjs';
2
2
  export { l as engineHarness } from '../engine-harness-LBfqbFSe.cjs';
3
3
  export { p as proofRunCore } from '../proof-run-core-B1GeqkR8.cjs';
4
- export { p as proofRunEngine } from '../proof-run-engine-DeHxtGnW.cjs';
4
+ export { p as proofRunEngine } from '../proof-run-engine-4dM37pEx.cjs';
5
5
  import '../types.cjs';
@@ -1,5 +1,5 @@
1
1
  export { b as runner } from '../runner-BdQpOkZD.js';
2
2
  export { l as engineHarness } from '../engine-harness-CMACHP6A.js';
3
3
  export { p as proofRunCore } from '../proof-run-core-B1GeqkR8.js';
4
- export { p as proofRunEngine } from '../proof-run-engine-DYfmd8d7.js';
4
+ export { p as proofRunEngine } from '../proof-run-engine-BqaeqAze.js';
5
5
  import '../types.js';
@@ -1,2 +1,2 @@
1
- export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from '../proof-run-engine-DeHxtGnW.cjs';
1
+ export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from '../proof-run-engine-4dM37pEx.cjs';
2
2
  import '../proof-run-core-B1GeqkR8.cjs';
@@ -1,2 +1,2 @@
1
- export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from '../proof-run-engine-DYfmd8d7.js';
1
+ export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from '../proof-run-engine-BqaeqAze.js';
2
2
  import '../proof-run-core-B1GeqkR8.js';
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
295
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
385
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "recon" | "author" | "ship" | "implement" | "verify" | "setup";
662
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
295
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "recon" | "author" | "ship" | "implement" | "verify" | "setup" | "run";
385
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "recon" | "author" | "ship" | "implement" | "verify" | "setup";
662
+ action: "author" | "recon" | "ship" | "implement" | "verify" | "setup";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
@@ -1,2 +1,2 @@
1
1
  import './proof-run-core-B1GeqkR8.cjs';
2
- export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from './proof-run-engine-DeHxtGnW.cjs';
2
+ export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from './proof-run-engine-4dM37pEx.cjs';
@@ -1,2 +1,2 @@
1
1
  import './proof-run-core-B1GeqkR8.js';
2
- export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from './proof-run-engine-DYfmd8d7.js';
2
+ export { R as RiddleProofEngine, c as createRiddleProofEngine, e as executeWorkflow } from './proof-run-engine-BqaeqAze.js';
@@ -444,6 +444,7 @@
444
444
  "verification_mode": "interaction",
445
445
  "server_path": "/",
446
446
  "wait_for_selector": "main#main-content",
447
+ "max_iterations": 6,
447
448
  "capture_script_contract": [
448
449
  "throw intentional-riddle-proof-regression-thrown-error from the capture script",
449
450
  "preserve the exact marker in terminal evidence",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.8.40",
3
+ "version": "0.8.42",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",
@@ -20,6 +20,7 @@ from util import ( # noqa: E402
20
20
  build_capture_script,
21
21
  capture_static_preview,
22
22
  capture_viewport_matrix_status,
23
+ compose_remote_capture_url,
23
24
  enrich_capture_payload,
24
25
  has_auth_context,
25
26
  invoke_retry,
@@ -41,6 +42,7 @@ MIN_CANVAS_AREA = 50000
41
42
  HYDRATION_WAIT_MS = 1500
42
43
  PAGE_STATE_PREFIX = 'RIDDLE_PROOF_STATE:'
43
44
  PROOF_EVIDENCE_PREFIX = 'RIDDLE_PROOF_EVIDENCE:'
45
+ INTERACTION_VERIFICATION_MODES = {'interaction', 'flow', 'browser_interaction'}
44
46
 
45
47
  s = load_state()
46
48
  after_dir = (s.get('after_worktree') or '').strip()
@@ -808,7 +810,7 @@ def capture_workspace_baseline(project_dir, label, plan, capture_script=''):
808
810
 
809
811
 
810
812
  def capture_prod_baseline(prod_url, plan, capture_script=''):
811
- target_url = (prod_url or '').strip()
813
+ target_url = prod_capture_target_url(prod_url, plan)
812
814
  if not target_url:
813
815
  raise SystemExit('Requested prod baseline in recon, but prod_url is missing.')
814
816
  wait_for_selector = (plan.get('wait_for_selector') or '').strip()
@@ -821,7 +823,7 @@ def capture_prod_baseline(prod_url, plan, capture_script=''):
821
823
  append_capture_diagnostic(s, 'prod', 'riddle_script', args, shot)
822
824
  record_recon_phase('prod_capture', 'completed', 'Production recon baseline capture completed.')
823
825
  return {
824
- 'source': 'prod_url',
826
+ 'source': 'prod_url_with_target_path' if target_url != (prod_url or '').strip() else 'prod_url',
825
827
  'mode': 'remote',
826
828
  'path': normalize_observed_path(target_url) or (plan.get('target_path') or '/'),
827
829
  'capture_url': target_url,
@@ -831,6 +833,19 @@ def capture_prod_baseline(prod_url, plan, capture_script=''):
831
833
  }
832
834
 
833
835
 
836
+ def interaction_verification_mode():
837
+ return str(s.get('verification_mode') or '').strip().lower() in INTERACTION_VERIFICATION_MODES
838
+
839
+
840
+ def prod_capture_target_url(prod_url, plan):
841
+ target_path = str((plan or {}).get('target_path') or '').strip()
842
+ has_explicit_start_route = bool(
843
+ str(s.get('server_path') or s.get('expected_start_path') or '').strip()
844
+ and (str(s.get('server_path_source') or '').strip() or interaction_verification_mode())
845
+ )
846
+ return compose_remote_capture_url(prod_url, target_path, explicit_target=has_explicit_start_route)
847
+
848
+
834
849
  def baseline_record(capture, observation):
835
850
  return {
836
851
  'source': capture.get('source'),
@@ -1066,7 +1081,7 @@ for label in required_baselines:
1066
1081
  expected_path = current_plan['target_path']
1067
1082
  else:
1068
1083
  capture = capture_prod_baseline(s.get('prod_url', ''), current_plan, capture_script='')
1069
- expected_path = urlparse(s.get('prod_url', '')).path or current_plan['target_path']
1084
+ expected_path = normalize_observed_path(capture.get('capture_url')) or current_plan['target_path']
1070
1085
  observation = build_observation_packet(label, expected_path, capture=capture)
1071
1086
  except SystemExit:
1072
1087
  raise
@@ -1,7 +1,7 @@
1
1
  """Shared helpers for Riddle Proof pipeline."""
2
2
 
3
3
  import hashlib, json, os, re, shlex, subprocess as sp, tempfile, time
4
- from urllib.parse import urljoin
4
+ from urllib.parse import urljoin, urlparse, urlunparse
5
5
  from urllib.request import urlopen
6
6
 
7
7
  STATE_FILE = os.environ.get('RIDDLE_PROOF_STATE_FILE', '/tmp/riddle-proof-state.json')
@@ -86,6 +86,44 @@ def normalize_browser_path(value):
86
86
  return value.lower() or '/'
87
87
 
88
88
 
89
+ def compose_remote_capture_url(base_url, target_path='', explicit_target=False):
90
+ """Resolve a remote capture URL against an explicit browser route.
91
+
92
+ prod_url identifies the deployed origin, but interaction proofs may start on
93
+ a route such as /proof/ before navigating elsewhere. In that case recon must
94
+ capture the start route, not merely the prod_url root.
95
+ """
96
+ base = str(base_url or '').strip()
97
+ target = str(target_path or '').strip()
98
+ if not base or not target.startswith('/'):
99
+ return base
100
+
101
+ parsed_base = urlparse(base)
102
+ if not parsed_base.scheme or not parsed_base.netloc:
103
+ return base
104
+
105
+ parsed_target = urlparse(target)
106
+ target_browser_path = parsed_target.path or '/'
107
+ if not target_browser_path.startswith('/'):
108
+ target_browser_path = '/' + target_browser_path.lstrip('/')
109
+
110
+ if not explicit_target:
111
+ base_browser_path = parsed_base.path or '/'
112
+ if normalize_browser_path(target_browser_path) in ('', '/') and normalize_browser_path(base_browser_path) != '/':
113
+ return base
114
+ if normalize_browser_path(target_browser_path) == normalize_browser_path(base_browser_path):
115
+ return base
116
+
117
+ return urlunparse((
118
+ parsed_base.scheme,
119
+ parsed_base.netloc,
120
+ target_browser_path,
121
+ '',
122
+ parsed_target.query,
123
+ parsed_target.fragment,
124
+ ))
125
+
126
+
89
127
  def extract_browser_paths(text):
90
128
  paths = []
91
129
  for match in re.findall(r'/(?:[A-Za-z0-9._~%!$&\'()*+,;=:@-]+/?)+(?:\?[A-Za-z0-9._~%!$&\'()*+,;=:@/?-]*)?', str(text or '')):
@@ -70,6 +70,35 @@ def load_module(name: str, path: Path):
70
70
  return module
71
71
 
72
72
 
73
+ def run_recon_remote_prod_capture_uses_interaction_start_route():
74
+ util = load_module('riddle_proof_util_route_target_smoke', UTIL_PATH)
75
+ cases = [
76
+ (
77
+ util.compose_remote_capture_url('https://riddledc.com/', '/proof/', explicit_target=True),
78
+ 'https://riddledc.com/proof/',
79
+ ),
80
+ (
81
+ util.compose_remote_capture_url('https://riddledc.com/', '/pricing/?rp_probe=1#pricing-probe', explicit_target=True),
82
+ 'https://riddledc.com/pricing/?rp_probe=1#pricing-probe',
83
+ ),
84
+ (
85
+ util.compose_remote_capture_url('https://riddledc.com/proof/', '/', explicit_target=True),
86
+ 'https://riddledc.com/',
87
+ ),
88
+ (
89
+ util.compose_remote_capture_url('https://riddledc.com/proof/', '/', explicit_target=False),
90
+ 'https://riddledc.com/proof/',
91
+ ),
92
+ ]
93
+ for observed, expected in cases:
94
+ assert observed == expected, f'expected {expected}, got {observed}'
95
+ return {
96
+ 'ok': True,
97
+ 'remote_start_route': 'https://riddledc.com/proof/',
98
+ 'query_hash_route': 'https://riddledc.com/pricing/?rp_probe=1#pricing-probe',
99
+ }
100
+
101
+
73
102
  class FakeRiddle:
74
103
  def __init__(self):
75
104
  self.calls = []
@@ -19,6 +19,12 @@ def load_smoke_module():
19
19
 
20
20
 
21
21
  CASES = [
22
+ {
23
+ 'name': 'recon-remote-prod-captures-interaction-start-route',
24
+ 'covers': ['route-changing interactions', 'no-diff prod audits'],
25
+ 'function': 'run_recon_remote_prod_capture_uses_interaction_start_route',
26
+ 'expected_terminal': 'pass',
27
+ },
22
28
  {
23
29
  'name': 'route-change-forward-pass',
24
30
  'covers': ['route-changing interactions', 'proof-evidence-present'],