@riddledc/riddle-proof 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -120,7 +120,7 @@ declare function buildSetupArgs(params: WorkflowParams, config: ReturnType<typeo
|
|
|
120
120
|
target_image_hash: string;
|
|
121
121
|
viewport_matrix_json: string;
|
|
122
122
|
deterministic_setup_json: string;
|
|
123
|
-
reference: "
|
|
123
|
+
reference: "before" | "prod" | "both";
|
|
124
124
|
base_branch: string;
|
|
125
125
|
before_ref: string;
|
|
126
126
|
allow_static_preview_fallback: string;
|
package/dist/proof-run-core.d.ts
CHANGED
|
@@ -120,7 +120,7 @@ declare function buildSetupArgs(params: WorkflowParams, config: ReturnType<typeo
|
|
|
120
120
|
target_image_hash: string;
|
|
121
121
|
viewport_matrix_json: string;
|
|
122
122
|
deterministic_setup_json: string;
|
|
123
|
-
reference: "
|
|
123
|
+
reference: "before" | "prod" | "both";
|
|
124
124
|
base_branch: string;
|
|
125
125
|
before_ref: string;
|
|
126
126
|
allow_static_preview_fallback: 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: "
|
|
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: "
|
|
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: "
|
|
662
|
+
action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
|
|
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: "
|
|
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: "
|
|
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: "
|
|
662
|
+
action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
|
|
663
663
|
state_path: string;
|
|
664
664
|
stage: any;
|
|
665
665
|
summary: string;
|
package/package.json
CHANGED
package/runtime/lib/verify.py
CHANGED
|
@@ -14,6 +14,7 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
14
14
|
from util import (
|
|
15
15
|
append_capture_diagnostic,
|
|
16
16
|
apply_auth_context,
|
|
17
|
+
build_capture_script,
|
|
17
18
|
build_visual_proof_session,
|
|
18
19
|
capture_proof_session_seed,
|
|
19
20
|
capture_static_preview,
|
|
@@ -21,6 +22,7 @@ from util import (
|
|
|
21
22
|
has_auth_context,
|
|
22
23
|
invoke,
|
|
23
24
|
invoke_retry,
|
|
25
|
+
join_url_path,
|
|
24
26
|
load_state,
|
|
25
27
|
prepare_server_preview,
|
|
26
28
|
record_successful_capture_hint,
|
|
@@ -86,6 +88,82 @@ def capture_script_saves_screenshot(script):
|
|
|
86
88
|
return 'saveScreenshot' in (script or '')
|
|
87
89
|
|
|
88
90
|
|
|
91
|
+
def explicitly_false(value):
|
|
92
|
+
if value is False:
|
|
93
|
+
return True
|
|
94
|
+
if isinstance(value, str):
|
|
95
|
+
return value.strip().lower() in ('false', '0', 'no', 'off')
|
|
96
|
+
return False
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def audit_no_diff_mode(state):
|
|
100
|
+
implementation_mode = str(state.get('implementation_mode') or '').strip().lower()
|
|
101
|
+
workflow_mode = str(state.get('workflow_mode') or '').strip().lower()
|
|
102
|
+
return (
|
|
103
|
+
state.get('implementation_status') == 'not_required'
|
|
104
|
+
or implementation_mode in ('none', 'audit', 'no_implementation', 'no-implementation')
|
|
105
|
+
or workflow_mode == 'audit'
|
|
106
|
+
or explicitly_false(state.get('require_diff'))
|
|
107
|
+
or explicitly_false(state.get('allow_code_changes'))
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def implementation_ready_for_verify(state):
|
|
112
|
+
if audit_no_diff_mode(state):
|
|
113
|
+
return True
|
|
114
|
+
return state.get('implementation_status') in ('changes_detected', 'completed')
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def visual_delta_required_for_state(state):
|
|
118
|
+
return visual_delta_applies(state.get('verification_mode')) and not audit_no_diff_mode(state)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def audit_current_capture_url(state, prod_url, expected_path):
|
|
122
|
+
target = (prod_url or '').strip()
|
|
123
|
+
server_path = (state.get('server_path') or '').strip()
|
|
124
|
+
if target:
|
|
125
|
+
parsed = urlparse(target)
|
|
126
|
+
if server_path and server_path != '/' and (not parsed.path or parsed.path == '/'):
|
|
127
|
+
return join_url_path(target, server_path)
|
|
128
|
+
return target
|
|
129
|
+
fallback = (state.get('target_url') or state.get('url') or '').strip()
|
|
130
|
+
if fallback:
|
|
131
|
+
return fallback
|
|
132
|
+
return ''
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def capture_current_target(state, target_url, label, capture_script, timeout=300):
|
|
136
|
+
script = build_capture_script(target_url, capture_script, label, state.get('wait_for_selector', ''))
|
|
137
|
+
args = {'script': script, 'timeout_sec': 60}
|
|
138
|
+
apply_auth_context(state, args)
|
|
139
|
+
shot = invoke_retry('riddle_script', args, retries=3, timeout=max(timeout, 120))
|
|
140
|
+
screenshots = shot.get('screenshots') or []
|
|
141
|
+
url = screenshots[0].get('url', '') if screenshots else extract_screenshot_url(shot, label)
|
|
142
|
+
return {
|
|
143
|
+
'ok': bool(url),
|
|
144
|
+
'capture_url': target_url,
|
|
145
|
+
'url': url,
|
|
146
|
+
'raw': shot,
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def baseline_payload_from_recon(state, results):
|
|
151
|
+
baseline = (results.get('baseline') or {}) if isinstance(results, dict) else {}
|
|
152
|
+
selected = baseline.get('prod') or baseline.get('before') or {}
|
|
153
|
+
url = selected.get('url') if isinstance(selected, dict) else ''
|
|
154
|
+
if not url:
|
|
155
|
+
return {'ok': False, 'error': 'Audit/no-diff verify has no current target URL and no recon screenshot to reuse.'}
|
|
156
|
+
return {
|
|
157
|
+
'ok': True,
|
|
158
|
+
'screenshots': [{'name': 'after-proof', 'url': url}],
|
|
159
|
+
'result': {
|
|
160
|
+
'audit_no_diff_reused_recon_baseline': True,
|
|
161
|
+
'baseline_source': selected.get('source') or 'recon',
|
|
162
|
+
'path': selected.get('path') or state.get('server_path') or '',
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
89
167
|
def normalized_verification_mode(value):
|
|
90
168
|
return ((value or 'proof').strip().lower() or 'proof')
|
|
91
169
|
|
|
@@ -1143,7 +1221,7 @@ def add_visual_delta_diagnostic(visual_delta, key, value):
|
|
|
1143
1221
|
|
|
1144
1222
|
|
|
1145
1223
|
def measure_visual_delta_against_baseline(state, results, after_payload, current_visual_delta):
|
|
1146
|
-
if not
|
|
1224
|
+
if not visual_delta_required_for_state(state):
|
|
1147
1225
|
return current_visual_delta
|
|
1148
1226
|
if isinstance(current_visual_delta, dict) and current_visual_delta.get('status') == 'measured':
|
|
1149
1227
|
return current_visual_delta
|
|
@@ -1438,6 +1516,14 @@ def artifact_contract_for_mode(verification_mode):
|
|
|
1438
1516
|
}
|
|
1439
1517
|
|
|
1440
1518
|
|
|
1519
|
+
def artifact_contract_for_state(state):
|
|
1520
|
+
contract = artifact_contract_for_mode(state.get('verification_mode'))
|
|
1521
|
+
if audit_no_diff_mode(state):
|
|
1522
|
+
contract['required']['visual_delta'] = False
|
|
1523
|
+
contract['optional']['visual_delta'] = True
|
|
1524
|
+
return contract
|
|
1525
|
+
|
|
1526
|
+
|
|
1441
1527
|
def artifact_production_summary(payload, supporting):
|
|
1442
1528
|
artifact_summary = summarize_capture_artifacts(payload)
|
|
1443
1529
|
return {
|
|
@@ -1484,7 +1570,7 @@ def artifact_signal_availability(state, after_observation, supporting, visual_de
|
|
|
1484
1570
|
|
|
1485
1571
|
|
|
1486
1572
|
def artifact_usage_summary(state, after_observation, supporting, visual_delta, required_baseline_present, semantic_context, evidence_basis):
|
|
1487
|
-
contract =
|
|
1573
|
+
contract = artifact_contract_for_state(state)
|
|
1488
1574
|
available = artifact_signal_availability(
|
|
1489
1575
|
state,
|
|
1490
1576
|
after_observation,
|
|
@@ -1810,14 +1896,21 @@ def build_evidence_bundle(state, results, after_payload, after_observation, requ
|
|
|
1810
1896
|
proof_evidence = extract_proof_evidence(after_payload)
|
|
1811
1897
|
playability_assessment = assess_playability_evidence(proof_evidence)
|
|
1812
1898
|
playability_evidence = extract_playability_evidence(proof_evidence)
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1899
|
+
if audit_no_diff_mode(state):
|
|
1900
|
+
visual_delta = {
|
|
1901
|
+
'status': 'not_applicable',
|
|
1902
|
+
'passed': None,
|
|
1903
|
+
'reason': 'Audit/no-diff verification judges current target evidence directly and does not require a before/after implementation delta.',
|
|
1904
|
+
}
|
|
1905
|
+
else:
|
|
1906
|
+
visual_delta = (
|
|
1907
|
+
extract_visual_delta(after_payload)
|
|
1908
|
+
if visual_delta_applies(state.get('verification_mode'))
|
|
1909
|
+
else {'status': 'not_applicable', 'passed': None, 'reason': 'Verification mode does not require visual delta gating.'}
|
|
1910
|
+
)
|
|
1818
1911
|
visual_delta = measure_visual_delta_against_baseline(state, results, after_payload, visual_delta)
|
|
1819
1912
|
semantic_context = build_semantic_context(state, results, after_observation, expected_path)
|
|
1820
|
-
artifact_contract =
|
|
1913
|
+
artifact_contract = artifact_contract_for_state(state)
|
|
1821
1914
|
artifact_production = artifact_production_summary(after_payload, supporting)
|
|
1822
1915
|
artifact_usage = artifact_usage_summary(
|
|
1823
1916
|
state,
|
|
@@ -1918,7 +2011,7 @@ def build_supervisor_assessment_request(state, payload, after_observation, requi
|
|
|
1918
2011
|
|
|
1919
2012
|
artifact_contract = (evidence_bundle or {}).get('artifact_contract') if isinstance(evidence_bundle, dict) else None
|
|
1920
2013
|
if not isinstance(artifact_contract, dict):
|
|
1921
|
-
artifact_contract =
|
|
2014
|
+
artifact_contract = artifact_contract_for_state(state)
|
|
1922
2015
|
artifact_production = (evidence_bundle or {}).get('artifact_production') if isinstance(evidence_bundle, dict) else None
|
|
1923
2016
|
if not isinstance(artifact_production, dict):
|
|
1924
2017
|
artifact_production = artifact_production_summary(payload, supporting)
|
|
@@ -1935,7 +2028,7 @@ def build_supervisor_assessment_request(state, payload, after_observation, requi
|
|
|
1935
2028
|
evidence_bundle['artifact_contract'] = artifact_contract
|
|
1936
2029
|
evidence_bundle['artifact_production'] = artifact_production
|
|
1937
2030
|
evidence_bundle['artifact_usage'] = artifact_usage
|
|
1938
|
-
visual_delta_blocker = visual_delta_blocker_for_mode(verification_mode, visual_delta)
|
|
2031
|
+
visual_delta_blocker = '' if audit_no_diff_mode(state) else visual_delta_blocker_for_mode(verification_mode, visual_delta)
|
|
1939
2032
|
hard_blockers = [visual_delta_blocker] if visual_delta_blocker else []
|
|
1940
2033
|
if verification_mode in PLAYABILITY_MODES and not supporting.get('playability_ready'):
|
|
1941
2034
|
assessment = supporting.get('playability_assessment') or {}
|
|
@@ -1946,6 +2039,30 @@ def build_supervisor_assessment_request(state, payload, after_observation, requi
|
|
|
1946
2039
|
+ (f': {detail}' if detail else '.')
|
|
1947
2040
|
)
|
|
1948
2041
|
|
|
2042
|
+
instructions = [
|
|
2043
|
+
'The supervising agent owns proof assessment. Inspect the recon baseline(s), after evidence, and any structured artifacts together.',
|
|
2044
|
+
'Decide whether the evidence is ready_to_ship or should continue internally through author, implement, or recon.',
|
|
2045
|
+
'Hard blockers cannot be overridden by supervisor judgment; if hard_blockers is non-empty, do not choose ready_to_ship.',
|
|
2046
|
+
'Do not mark ready_to_ship if the before/prod baseline is blank, shell-only, generic, or not visibly tied to the requested feature.',
|
|
2047
|
+
'Use semantic_context.route plus headings/buttons/text anchors to ground route and content judgment before treating a screenshot as wrong-route.',
|
|
2048
|
+
'For visual/UI modes, use screenshots plus after_observation.details.visible_text_sample, headings, buttons, links, canvas_count, and large_visible_elements to explain what the proof actually shows.',
|
|
2049
|
+
]
|
|
2050
|
+
if audit_no_diff_mode(state):
|
|
2051
|
+
instructions.append(
|
|
2052
|
+
'Audit/no-diff mode intentionally has implementation_status=not_required and visual_delta.status=not_applicable; judge the current target evidence directly instead of requiring an implementation diff.'
|
|
2053
|
+
)
|
|
2054
|
+
else:
|
|
2055
|
+
instructions.append(
|
|
2056
|
+
'For visual/UI polish, capture success is not proof. If visual_delta.status is unmeasured, missing, not_applicable, or measured with passed=false, choose needs_implementation or needs_richer_proof instead of ready_to_ship.'
|
|
2057
|
+
)
|
|
2058
|
+
instructions.extend([
|
|
2059
|
+
'For playable/gameplay proof, screenshots are supporting evidence only. Do not mark ready_to_ship unless playability_assessment.passed is true and the proof shows accepted input, state/time progression, and playfield/canvas pixel motion.',
|
|
2060
|
+
'For data/audio/log/metrics/custom modes, judge the structured evidence bundle and proof_evidence_sample directly; screenshots are optional supporting context.',
|
|
2061
|
+
'The summary must name the concrete change, the target route/UI, what changed in after evidence, and why the stop condition is satisfied.',
|
|
2062
|
+
'Only set escalation_target=human when you conclude the workflow has hit a real wall or is not converging.',
|
|
2063
|
+
'Pass the judgment back via proof_assessment_json and resume the workflow.',
|
|
2064
|
+
])
|
|
2065
|
+
|
|
1949
2066
|
return {
|
|
1950
2067
|
'status': 'needs_supervising_agent_assessment',
|
|
1951
2068
|
'verification_mode': verification_mode,
|
|
@@ -1961,20 +2078,7 @@ def build_supervisor_assessment_request(state, payload, after_observation, requi
|
|
|
1961
2078
|
'artifact_production': artifact_production,
|
|
1962
2079
|
'artifact_usage': artifact_usage,
|
|
1963
2080
|
'hard_blockers': hard_blockers,
|
|
1964
|
-
'instructions':
|
|
1965
|
-
'The supervising agent owns proof assessment. Inspect the recon baseline(s), after evidence, and any structured artifacts together.',
|
|
1966
|
-
'Decide whether the evidence is ready_to_ship or should continue internally through author, implement, or recon.',
|
|
1967
|
-
'Hard blockers cannot be overridden by supervisor judgment; if hard_blockers is non-empty, do not choose ready_to_ship.',
|
|
1968
|
-
'Do not mark ready_to_ship if the before/prod baseline is blank, shell-only, generic, or not visibly tied to the requested feature.',
|
|
1969
|
-
'Use semantic_context.route plus headings/buttons/text anchors to ground route and content judgment before treating a screenshot as wrong-route.',
|
|
1970
|
-
'For visual/UI modes, use screenshots plus after_observation.details.visible_text_sample, headings, buttons, links, canvas_count, and large_visible_elements to explain what the proof actually shows.',
|
|
1971
|
-
'For visual/UI polish, capture success is not proof. If visual_delta.status is unmeasured, missing, not_applicable, or measured with passed=false, choose needs_implementation or needs_richer_proof instead of ready_to_ship.',
|
|
1972
|
-
'For playable/gameplay proof, screenshots are supporting evidence only. Do not mark ready_to_ship unless playability_assessment.passed is true and the proof shows accepted input, state/time progression, and playfield/canvas pixel motion.',
|
|
1973
|
-
'For data/audio/log/metrics/custom modes, judge the structured evidence bundle and proof_evidence_sample directly; screenshots are optional supporting context.',
|
|
1974
|
-
'The summary must name the concrete change, the target route/UI, what changed in after evidence, and why the stop condition is satisfied.',
|
|
1975
|
-
'Only set escalation_target=human when you conclude the workflow has hit a real wall or is not converging.',
|
|
1976
|
-
'Pass the judgment back via proof_assessment_json and resume the workflow.',
|
|
1977
|
-
],
|
|
2081
|
+
'instructions': instructions,
|
|
1978
2082
|
'response_schema': {
|
|
1979
2083
|
'decision': 'ready_to_ship | needs_richer_proof | revise_capture | needs_recon | needs_implementation',
|
|
1980
2084
|
'summary': 'string',
|
|
@@ -1992,14 +2096,22 @@ capture_script = (s.get('capture_script') or '').strip()
|
|
|
1992
2096
|
if not capture_script:
|
|
1993
2097
|
raise SystemExit('capture_script not set in state. Recon should finish homework first, then verify should receive the real capture plan.')
|
|
1994
2098
|
|
|
1995
|
-
|
|
2099
|
+
no_implementation_mode = audit_no_diff_mode(s)
|
|
2100
|
+
if not implementation_ready_for_verify(s):
|
|
1996
2101
|
raise SystemExit('Implementation not recorded. Make the code changes and run riddle-proof-implement before verify.')
|
|
2102
|
+
if no_implementation_mode and s.get('implementation_status') != 'not_required':
|
|
2103
|
+
s['implementation_status'] = 'not_required'
|
|
2104
|
+
s['implementation_mode'] = s.get('implementation_mode') or 'none'
|
|
2105
|
+
if 'require_diff' not in s:
|
|
2106
|
+
s['require_diff'] = False
|
|
2107
|
+
if 'allow_code_changes' not in s:
|
|
2108
|
+
s['allow_code_changes'] = False
|
|
1997
2109
|
|
|
1998
2110
|
mode = s.get('mode', 'server')
|
|
1999
2111
|
reference = s.get('requested_reference') or s.get('reference', 'both')
|
|
2000
2112
|
prod_url = (s.get('prod_url') or '').strip()
|
|
2001
2113
|
after_dir = s.get('after_worktree', '').strip()
|
|
2002
|
-
if not after_dir or not os.path.exists(after_dir):
|
|
2114
|
+
if not no_implementation_mode and (not after_dir or not os.path.exists(after_dir)):
|
|
2003
2115
|
raise SystemExit('after_worktree not found. Run setup first.')
|
|
2004
2116
|
|
|
2005
2117
|
build_cmd = s.get('build_command', 'npm run build')
|
|
@@ -2069,82 +2181,122 @@ if existing_before:
|
|
|
2069
2181
|
if existing_prod:
|
|
2070
2182
|
print('Prod baseline: ' + existing_prod)
|
|
2071
2183
|
|
|
2072
|
-
# AFTER (always from after worktree)
|
|
2073
|
-
record_verify_phase('build', 'running', 'Building after worktree for verify capture.')
|
|
2074
|
-
print('Building after worktree...')
|
|
2075
|
-
build_attempt = run_project_build(after_dir, build_cmd, timeout=600, clean_cache_dir='.next')
|
|
2076
|
-
br = build_attempt.get('result')
|
|
2077
|
-
if build_attempt.get('clean_retry_used'):
|
|
2078
|
-
print('Verify build recovered after cleaning .next cache.')
|
|
2079
|
-
if br.returncode != 0:
|
|
2080
|
-
record_verify_phase('build', 'failed', 'After build failed: ' + br.stderr[:300])
|
|
2081
|
-
raise SystemExit('After build failed: ' + br.stderr[:500])
|
|
2082
|
-
if build_attempt.get('attempts'):
|
|
2083
|
-
s['verify_build_attempts'] = build_attempt['attempts']
|
|
2084
|
-
s['verify_build_clean_retry_used'] = bool(build_attempt.get('clean_retry_used'))
|
|
2085
|
-
record_verify_phase('build', 'completed', 'After worktree build completed.')
|
|
2086
|
-
|
|
2087
2184
|
after_payload = {}
|
|
2088
|
-
|
|
2089
|
-
record_verify_phase('
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
'
|
|
2095
|
-
'
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2185
|
+
if no_implementation_mode:
|
|
2186
|
+
record_verify_phase('build', 'completed', 'Audit/no-diff mode skips after-worktree build.')
|
|
2187
|
+
current_url = audit_current_capture_url(s, prod_url, expected_path)
|
|
2188
|
+
record_verify_phase('capture', 'running', 'Capturing current target evidence for audit/no-diff verify.')
|
|
2189
|
+
if current_url:
|
|
2190
|
+
print('Audit/no-diff verify capture at: ' + current_url)
|
|
2191
|
+
capture = capture_current_target(s, current_url, 'after-proof', probe_capture_script, timeout=300)
|
|
2192
|
+
after_payload = capture.get('raw') or capture
|
|
2193
|
+
append_capture_diagnostic(
|
|
2194
|
+
s,
|
|
2195
|
+
'after',
|
|
2196
|
+
'riddle_script',
|
|
2197
|
+
{'target_url': current_url, 'audit_no_diff': True},
|
|
2198
|
+
after_payload,
|
|
2199
|
+
)
|
|
2200
|
+
capture_error = capture_payload_error(after_payload)
|
|
2201
|
+
if capture_error:
|
|
2202
|
+
abort_capture_failure(s, results, expected_path, capture_error, after_payload)
|
|
2203
|
+
results['after'] = {'screenshots': [{'url': capture.get('url', '')}] if capture.get('url') else [], 'raw': after_payload}
|
|
2204
|
+
s['after_cdn'] = capture.get('url', '')
|
|
2205
|
+
s['after_capture_source'] = 'audit_current_target'
|
|
2206
|
+
s['audit_current_url'] = current_url
|
|
2207
|
+
else:
|
|
2208
|
+
print('Audit/no-diff verify has no current target URL; reusing recon screenshot as current evidence.')
|
|
2209
|
+
after_payload = baseline_payload_from_recon(s, results)
|
|
2210
|
+
append_capture_diagnostic(
|
|
2211
|
+
s,
|
|
2212
|
+
'after',
|
|
2213
|
+
'recon_baseline_reuse',
|
|
2214
|
+
{'audit_no_diff': True},
|
|
2215
|
+
after_payload,
|
|
2216
|
+
)
|
|
2217
|
+
capture_error = capture_payload_error(after_payload)
|
|
2218
|
+
if capture_error:
|
|
2219
|
+
abort_capture_failure(s, results, expected_path, capture_error, after_payload)
|
|
2220
|
+
url = extract_screenshot_url(after_payload, 'after-proof')
|
|
2221
|
+
results['after'] = {'screenshots': [{'url': url}] if url else [], 'raw': after_payload}
|
|
2222
|
+
s['after_cdn'] = url
|
|
2223
|
+
s['after_capture_source'] = 'audit_recon_baseline'
|
|
2127
2224
|
else:
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
'
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2225
|
+
# AFTER (from after worktree)
|
|
2226
|
+
record_verify_phase('build', 'running', 'Building after worktree for verify capture.')
|
|
2227
|
+
print('Building after worktree...')
|
|
2228
|
+
build_attempt = run_project_build(after_dir, build_cmd, timeout=600, clean_cache_dir='.next')
|
|
2229
|
+
br = build_attempt.get('result')
|
|
2230
|
+
if build_attempt.get('clean_retry_used'):
|
|
2231
|
+
print('Verify build recovered after cleaning .next cache.')
|
|
2232
|
+
if br.returncode != 0:
|
|
2233
|
+
record_verify_phase('build', 'failed', 'After build failed: ' + br.stderr[:300])
|
|
2234
|
+
raise SystemExit('After build failed: ' + br.stderr[:500])
|
|
2235
|
+
if build_attempt.get('attempts'):
|
|
2236
|
+
s['verify_build_attempts'] = build_attempt['attempts']
|
|
2237
|
+
s['verify_build_clean_retry_used'] = bool(build_attempt.get('clean_retry_used'))
|
|
2238
|
+
record_verify_phase('build', 'completed', 'After worktree build completed.')
|
|
2239
|
+
|
|
2240
|
+
static_reason = should_use_static_preview(after_dir, s) if mode == 'server' else ''
|
|
2241
|
+
record_verify_phase('capture', 'running', 'Capturing after-proof evidence.')
|
|
2242
|
+
if mode == 'server' and not static_reason:
|
|
2243
|
+
build_dir, server_command, server_exclude = prepare_server_preview(after_dir, s)
|
|
2244
|
+
|
|
2245
|
+
server_args = {
|
|
2246
|
+
'directory': build_dir,
|
|
2247
|
+
'image': s['server_image'],
|
|
2248
|
+
'command': server_command,
|
|
2249
|
+
'port': int(s['server_port']),
|
|
2250
|
+
'wait_until': 'domcontentloaded',
|
|
2251
|
+
'readiness_timeout': 180,
|
|
2252
|
+
'timeout': 300,
|
|
2253
|
+
'env': {'PORT': str(s['server_port']), 'HOSTNAME': '0.0.0.0'},
|
|
2254
|
+
'exclude': server_exclude,
|
|
2255
|
+
}
|
|
2256
|
+
if s.get('server_path'):
|
|
2257
|
+
server_args['path'] = s['server_path']
|
|
2258
|
+
server_args['readiness_path'] = '/' if has_auth_context(s) else s['server_path']
|
|
2259
|
+
if s.get('color_scheme'):
|
|
2260
|
+
server_args['color_scheme'] = s['color_scheme']
|
|
2261
|
+
if s.get('wait_for_selector'):
|
|
2262
|
+
server_args['wait_for_selector'] = s['wait_for_selector']
|
|
2263
|
+
apply_auth_context(s, server_args)
|
|
2264
|
+
server_args['script'] = probe_capture_script
|
|
2265
|
+
|
|
2266
|
+
print('Running after server preview from: ' + build_dir)
|
|
2267
|
+
shot = invoke_retry('riddle_server_preview', server_args, retries=3, timeout=420)
|
|
2268
|
+
append_capture_diagnostic(s, 'after', 'riddle_server_preview', server_args, shot)
|
|
2269
|
+
after_payload = shot
|
|
2270
|
+
capture_error = capture_payload_error(after_payload)
|
|
2271
|
+
if capture_error:
|
|
2272
|
+
abort_capture_failure(s, results, expected_path, capture_error, after_payload)
|
|
2273
|
+
url = extract_screenshot_url(shot, 'after-proof')
|
|
2274
|
+
if not url:
|
|
2275
|
+
print('WARNING: After server preview no screenshot.')
|
|
2276
|
+
results['after'] = {'screenshots': [{'url': url}] if url else [], 'raw': shot}
|
|
2277
|
+
s['after_cdn'] = url
|
|
2278
|
+
|
|
2279
|
+
else:
|
|
2280
|
+
if static_reason:
|
|
2281
|
+
print('Static preview fallback for after capture: ' + static_reason)
|
|
2282
|
+
old_id = s.get('after_preview_id', '')
|
|
2283
|
+
if old_id:
|
|
2284
|
+
invoke('riddle_preview_delete', {'id': old_id}, timeout=30)
|
|
2285
|
+
capture = capture_static_preview(s, after_dir, 'after', probe_capture_script, timeout=300, target_path=s.get('server_path', ''))
|
|
2286
|
+
s['after_preview_id'] = capture.get('preview_id', '')
|
|
2287
|
+
after_payload = ((capture.get('raw') or {}).get('capture') or (capture.get('raw') or {}) or capture)
|
|
2288
|
+
append_capture_diagnostic(
|
|
2289
|
+
s,
|
|
2290
|
+
'after',
|
|
2291
|
+
'riddle_static_preview',
|
|
2292
|
+
{'target_path': s.get('server_path', ''), 'static_fallback_reason': static_reason},
|
|
2293
|
+
after_payload,
|
|
2294
|
+
)
|
|
2295
|
+
capture_error = capture_payload_error(after_payload)
|
|
2296
|
+
if capture_error:
|
|
2297
|
+
abort_capture_failure(s, results, expected_path, capture_error, after_payload)
|
|
2298
|
+
results['after'] = {'screenshots': [{'url': capture.get('url', '')}] if capture.get('url') else [], 'raw': capture.get('raw')}
|
|
2299
|
+
s['after_cdn'] = capture.get('url', '')
|
|
2148
2300
|
|
|
2149
2301
|
after_observation = evaluate_capture_quality(after_payload, expected_path, verification_mode)
|
|
2150
2302
|
results['after']['observation'] = after_observation
|
|
@@ -2237,7 +2389,7 @@ if s.get('proof_session_artifact_url'):
|
|
|
2237
2389
|
visual_delta = ((evidence_bundle.get('after') or {}).get('visual_delta') or {})
|
|
2238
2390
|
if visual_delta.get('status') != 'not_applicable':
|
|
2239
2391
|
summary_lines.append('Visual delta gate: ' + compact_value(visual_delta, limit=700))
|
|
2240
|
-
visual_delta_blocker = visual_delta_blocker_for_mode(s.get('verification_mode'), visual_delta)
|
|
2392
|
+
visual_delta_blocker = '' if no_implementation_mode else visual_delta_blocker_for_mode(s.get('verification_mode'), visual_delta)
|
|
2241
2393
|
if visual_delta_blocker:
|
|
2242
2394
|
summary_lines.append('Visual delta hard gate: ' + visual_delta_blocker)
|
|
2243
2395
|
|
|
@@ -2257,7 +2409,7 @@ visual_delta_recovery = build_visual_delta_recovery_decision(
|
|
|
2257
2409
|
s.get('verification_mode'),
|
|
2258
2410
|
visual_delta,
|
|
2259
2411
|
visual_delta_blocker,
|
|
2260
|
-
)
|
|
2412
|
+
) if not no_implementation_mode else None
|
|
2261
2413
|
if visual_delta_recovery:
|
|
2262
2414
|
summary_lines.append('Visual delta recovery: ' + visual_delta_recovery['summary'])
|
|
2263
2415
|
|
|
@@ -2285,15 +2437,19 @@ if has_good_evidence:
|
|
|
2285
2437
|
s['proof_assessment'] = {}
|
|
2286
2438
|
s['proof_assessment_source'] = None
|
|
2287
2439
|
s['proof_assessment_request'] = supervisor_request
|
|
2440
|
+
next_stage_options = ['verify', 'author', 'recon'] if no_implementation_mode else ['verify', 'author', 'implement', 'ship', 'recon']
|
|
2441
|
+
fields_agent_may_update = ['proof_assessment_json', 'capture_script', 'server_path', 'wait_for_selector', 'proof_plan', 'assertions_json']
|
|
2442
|
+
if not no_implementation_mode:
|
|
2443
|
+
fields_agent_may_update.append('implementation_notes')
|
|
2288
2444
|
s['verify_decision_request'] = {
|
|
2289
2445
|
'status': s['verify_status'],
|
|
2290
2446
|
'summary': 'Verify captured usable evidence and is waiting for supervising-agent proof assessment.',
|
|
2291
2447
|
'expected_path': expected_path,
|
|
2292
2448
|
'latest_observation': after_observation,
|
|
2293
|
-
'next_stage_options':
|
|
2449
|
+
'next_stage_options': next_stage_options,
|
|
2294
2450
|
'recommended_stage': None,
|
|
2295
2451
|
'continue_with_stage': None,
|
|
2296
|
-
'fields_agent_may_update':
|
|
2452
|
+
'fields_agent_may_update': fields_agent_may_update,
|
|
2297
2453
|
'assessment_request': supervisor_request,
|
|
2298
2454
|
'instructions': [
|
|
2299
2455
|
'Inspect the recon baseline(s), after evidence, and any structured artifacts together.',
|
|
@@ -2305,6 +2461,7 @@ if has_good_evidence:
|
|
|
2305
2461
|
summary_lines.append('Proof next stage: supervising agent decides after reviewing the evidence packet')
|
|
2306
2462
|
else:
|
|
2307
2463
|
capture_retry = visual_delta_recovery or build_capture_retry_decision(after_observation, required_baseline_present, proof_evidence_blocker)
|
|
2464
|
+
next_stage_options = ['author', 'verify', 'recon'] if no_implementation_mode else ['author', 'verify', 'implement', 'recon']
|
|
2308
2465
|
s['verify_status'] = 'capture_incomplete'
|
|
2309
2466
|
s['merge_recommendation'] = 'do-not-merge'
|
|
2310
2467
|
s['proof_assessment'] = {}
|
|
@@ -2316,7 +2473,7 @@ else:
|
|
|
2316
2473
|
'expected_path': expected_path,
|
|
2317
2474
|
'latest_observation': after_observation,
|
|
2318
2475
|
'capture_quality': capture_retry,
|
|
2319
|
-
'next_stage_options':
|
|
2476
|
+
'next_stage_options': next_stage_options,
|
|
2320
2477
|
'recommended_stage': capture_retry.get('recommended_stage') or 'author',
|
|
2321
2478
|
'continue_with_stage': capture_retry.get('continue_with_stage') or 'author',
|
|
2322
2479
|
'fields_agent_may_update': ['capture_script', 'server_path', 'wait_for_selector', 'proof_plan'],
|
|
@@ -15,8 +15,27 @@ steps:
|
|
|
15
15
|
s = json.load(open(state_file))
|
|
16
16
|
if not s.get('workspace_ready'):
|
|
17
17
|
raise SystemExit('Workspace not ready. Run riddle-proof-setup first.')
|
|
18
|
-
|
|
18
|
+
implementation_mode = str(s.get('implementation_mode') or '').strip().lower()
|
|
19
|
+
workflow_mode = str(s.get('workflow_mode') or '').strip().lower()
|
|
20
|
+
require_diff = s.get('require_diff')
|
|
21
|
+
allow_code_changes = s.get('allow_code_changes')
|
|
22
|
+
def explicitly_false(value):
|
|
23
|
+
return value is False or str(value).strip().lower() in ('false', '0', 'no', 'off')
|
|
24
|
+
no_implementation_mode = (
|
|
25
|
+
s.get('implementation_status') == 'not_required'
|
|
26
|
+
or implementation_mode in ('none', 'audit', 'no_implementation', 'no-implementation')
|
|
27
|
+
or workflow_mode == 'audit'
|
|
28
|
+
or explicitly_false(require_diff)
|
|
29
|
+
or explicitly_false(allow_code_changes)
|
|
30
|
+
)
|
|
31
|
+
if not no_implementation_mode and s.get('implementation_status') not in ('changes_detected', 'completed'):
|
|
19
32
|
raise SystemExit('Implementation not recorded. Run riddle-proof-implement after making code changes.')
|
|
33
|
+
if no_implementation_mode:
|
|
34
|
+
s['implementation_status'] = 'not_required'
|
|
35
|
+
s['implementation_mode'] = s.get('implementation_mode') or 'none'
|
|
36
|
+
s.setdefault('require_diff', False)
|
|
37
|
+
s.setdefault('allow_code_changes', False)
|
|
38
|
+
json.dump(s, open(state_file, 'w'), indent=2)
|
|
20
39
|
print('VERIFY — ' + s.get('mode', 'server').upper())
|
|
21
40
|
print('Proof goal: ' + s.get('change_request', ''))
|
|
22
41
|
print('Success criteria: ' + (s.get('success_criteria') or '(none provided)'))
|
|
@@ -27,7 +46,10 @@ steps:
|
|
|
27
46
|
if s.get('prod_cdn'):
|
|
28
47
|
print('Prod baseline: ' + s.get('prod_cdn'))
|
|
29
48
|
after_dir = s.get('after_worktree', '')
|
|
30
|
-
|
|
49
|
+
if no_implementation_mode:
|
|
50
|
+
print('After worktree: not required for audit/no-diff verify')
|
|
51
|
+
else:
|
|
52
|
+
print('After worktree: ' + after_dir + (' (exists)' if os.path.exists(after_dir) else ' (MISSING)'))
|
|
31
53
|
PYEOF
|
|
32
54
|
|
|
33
55
|
- id: run_verify
|