@riddledc/riddle-proof 0.8.2 → 0.8.4
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/adapters/openclaw.js +4 -4
- package/dist/advanced/engine-harness.cjs +33 -11
- package/dist/advanced/engine-harness.js +4 -4
- package/dist/advanced/index.cjs +33 -11
- package/dist/advanced/index.d.cts +1 -1
- package/dist/advanced/index.d.ts +1 -1
- package/dist/advanced/index.js +6 -6
- package/dist/advanced/proof-run-engine.cjs +28 -8
- package/dist/advanced/proof-run-engine.d.cts +1 -1
- package/dist/advanced/proof-run-engine.d.ts +1 -1
- package/dist/advanced/proof-run-engine.js +1 -1
- package/dist/advanced/runner.js +4 -4
- package/dist/checkpoint.cjs +3 -1
- package/dist/checkpoint.js +1 -1
- package/dist/{chunk-SKIAZTQ7.js → chunk-4FOHZ7JG.js} +3 -1
- package/dist/{chunk-U4FUFBSH.js → chunk-FMOYUYH2.js} +1 -1
- package/dist/{chunk-YB5ACBZE.js → chunk-IP64JLLR.js} +5 -5
- package/dist/{chunk-OIFHYMHP.js → chunk-LZFCIHDT.js} +2 -2
- package/dist/{chunk-TZ3YMCDM.js → chunk-P22V26PS.js} +28 -8
- package/dist/{chunk-SMBZT46I.js → chunk-RBWSCU6V.js} +1 -1
- package/dist/{chunk-ZX45XGDJ.js → chunk-UIJ7X63P.js} +1 -1
- package/dist/{chunk-TNCDVE5O.js → chunk-YZUVEJ5B.js} +1 -1
- package/dist/cli/index.js +5 -5
- package/dist/cli.cjs +33 -11
- package/dist/cli.js +5 -5
- package/dist/engine-harness.cjs +33 -11
- package/dist/engine-harness.js +4 -4
- package/dist/index.cjs +33 -11
- package/dist/index.js +5 -5
- package/dist/openclaw.js +4 -4
- package/dist/{proof-run-engine-CVnboNHj.d.cts → proof-run-engine-B7DCPzpK.d.cts} +3 -3
- package/dist/{proof-run-engine-BVkeO-Yo.d.ts → proof-run-engine-BomAcXhA.d.ts} +3 -3
- package/dist/proof-run-engine.cjs +28 -8
- package/dist/proof-run-engine.d.cts +1 -1
- package/dist/proof-run-engine.d.ts +1 -1
- package/dist/proof-run-engine.js +1 -1
- package/dist/run-card.js +2 -2
- package/dist/runner.js +4 -4
- package/dist/spec/checkpoint.cjs +3 -1
- package/dist/spec/checkpoint.js +1 -1
- package/dist/spec/index.cjs +3 -1
- package/dist/spec/index.js +3 -3
- package/dist/spec/run-card.js +2 -2
- package/dist/spec/state.js +3 -3
- package/dist/state.js +3 -3
- package/package.json +1 -1
- package/runtime/lib/util.py +57 -0
- package/runtime/lib/verify.py +128 -5
- package/runtime/pipelines/riddle-proof-author.lobster +2 -1
- package/runtime/pipelines/riddle-proof-implement.lobster +2 -1
- package/runtime/pipelines/riddle-proof-recon.lobster +2 -1
- package/runtime/pipelines/riddle-proof-setup.lobster +4 -2
- package/runtime/pipelines/riddle-proof-ship.lobster +2 -1
- package/runtime/pipelines/riddle-proof-verify.lobster +2 -1
- package/runtime/tests/recon_verify_smoke.py +116 -0
package/dist/runner.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runRiddleProof
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-UIJ7X63P.js";
|
|
4
|
+
import "./chunk-YZUVEJ5B.js";
|
|
5
|
+
import "./chunk-FMOYUYH2.js";
|
|
6
6
|
import "./chunk-RV6LK7HU.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-4FOHZ7JG.js";
|
|
8
8
|
import "./chunk-VY4Y5U57.js";
|
|
9
9
|
import "./chunk-MLKGABMK.js";
|
|
10
10
|
export {
|
package/dist/spec/checkpoint.cjs
CHANGED
|
@@ -121,7 +121,7 @@ function responseSchemaForAuthorPacket() {
|
|
|
121
121
|
summary: { type: "string" },
|
|
122
122
|
payload: {
|
|
123
123
|
type: "object",
|
|
124
|
-
description: "For decision=author_packet, provide the proof packet itself or {author_packet:{...}} with proof_plan and
|
|
124
|
+
description: "For decision=author_packet, provide the proof packet itself or {author_packet:{...}} with proof_plan, capture_script, and refined_inputs.expected_terminal_path when the proof changes route, query, or hash."
|
|
125
125
|
},
|
|
126
126
|
reasons: { type: "array", items: { type: "string" } },
|
|
127
127
|
continue_with_stage: { type: "string", enum: ["author", "recon"] },
|
|
@@ -428,9 +428,11 @@ function buildAuthorCheckpointPacket(input) {
|
|
|
428
428
|
repo: input.request.repo || fullState.repo,
|
|
429
429
|
branch: input.request.branch || fullState.branch,
|
|
430
430
|
verification_mode: input.request.verification_mode || fullState.verification_mode,
|
|
431
|
+
success_criteria: fullState.success_criteria,
|
|
431
432
|
reference: input.request.reference || fullState.reference,
|
|
432
433
|
server_path: fullState.server_path,
|
|
433
434
|
wait_for_selector: fullState.wait_for_selector,
|
|
435
|
+
route_expectation: jsonCloneRecord(fullState.route_expectation),
|
|
434
436
|
author_summary: fullState.author_summary,
|
|
435
437
|
author_request: jsonCloneRecord(authorRequest),
|
|
436
438
|
recon_baseline_understanding: jsonCloneRecord(fullState.recon_baseline_understanding),
|
package/dist/spec/checkpoint.js
CHANGED
package/dist/spec/index.cjs
CHANGED
|
@@ -344,7 +344,7 @@ function responseSchemaForAuthorPacket() {
|
|
|
344
344
|
summary: { type: "string" },
|
|
345
345
|
payload: {
|
|
346
346
|
type: "object",
|
|
347
|
-
description: "For decision=author_packet, provide the proof packet itself or {author_packet:{...}} with proof_plan and
|
|
347
|
+
description: "For decision=author_packet, provide the proof packet itself or {author_packet:{...}} with proof_plan, capture_script, and refined_inputs.expected_terminal_path when the proof changes route, query, or hash."
|
|
348
348
|
},
|
|
349
349
|
reasons: { type: "array", items: { type: "string" } },
|
|
350
350
|
continue_with_stage: { type: "string", enum: ["author", "recon"] },
|
|
@@ -651,9 +651,11 @@ function buildAuthorCheckpointPacket(input) {
|
|
|
651
651
|
repo: input.request.repo || fullState.repo,
|
|
652
652
|
branch: input.request.branch || fullState.branch,
|
|
653
653
|
verification_mode: input.request.verification_mode || fullState.verification_mode,
|
|
654
|
+
success_criteria: fullState.success_criteria,
|
|
654
655
|
reference: input.request.reference || fullState.reference,
|
|
655
656
|
server_path: fullState.server_path,
|
|
656
657
|
wait_for_selector: fullState.wait_for_selector,
|
|
658
|
+
route_expectation: jsonCloneRecord(fullState.route_expectation),
|
|
657
659
|
author_summary: fullState.author_summary,
|
|
658
660
|
author_request: jsonCloneRecord(authorRequest),
|
|
659
661
|
recon_baseline_understanding: jsonCloneRecord(fullState.recon_baseline_understanding),
|
package/dist/spec/index.js
CHANGED
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
normalizePrLifecycleState,
|
|
11
11
|
normalizeRunParams,
|
|
12
12
|
setRunStatus
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-YZUVEJ5B.js";
|
|
14
14
|
import {
|
|
15
15
|
RIDDLE_PROOF_RUN_CARD_VERSION,
|
|
16
16
|
createRiddleProofRunCard
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-FMOYUYH2.js";
|
|
18
18
|
import {
|
|
19
19
|
RIDDLE_PROOF_CHECKPOINT_PACKET_VERSION,
|
|
20
20
|
RIDDLE_PROOF_CHECKPOINT_RESPONSE_VERSION,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
normalizeCheckpointResponse,
|
|
31
31
|
proofContractFromAuthorCheckpointResponse,
|
|
32
32
|
statePathsForRunState
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-4FOHZ7JG.js";
|
|
34
34
|
import {
|
|
35
35
|
applyTerminalMetadata,
|
|
36
36
|
compactRecord,
|
package/dist/spec/run-card.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RIDDLE_PROOF_RUN_CARD_VERSION,
|
|
3
3
|
createRiddleProofRunCard
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-FMOYUYH2.js";
|
|
5
|
+
import "../chunk-4FOHZ7JG.js";
|
|
6
6
|
import "../chunk-VY4Y5U57.js";
|
|
7
7
|
import "../chunk-MLKGABMK.js";
|
|
8
8
|
export {
|
package/dist/spec/state.js
CHANGED
|
@@ -9,9 +9,9 @@ import {
|
|
|
9
9
|
normalizePrLifecycleState,
|
|
10
10
|
normalizeRunParams,
|
|
11
11
|
setRunStatus
|
|
12
|
-
} from "../chunk-
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
12
|
+
} from "../chunk-YZUVEJ5B.js";
|
|
13
|
+
import "../chunk-FMOYUYH2.js";
|
|
14
|
+
import "../chunk-4FOHZ7JG.js";
|
|
15
15
|
import "../chunk-VY4Y5U57.js";
|
|
16
16
|
import "../chunk-MLKGABMK.js";
|
|
17
17
|
export {
|
package/dist/state.js
CHANGED
|
@@ -9,9 +9,9 @@ import {
|
|
|
9
9
|
normalizePrLifecycleState,
|
|
10
10
|
normalizeRunParams,
|
|
11
11
|
setRunStatus
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-YZUVEJ5B.js";
|
|
13
|
+
import "./chunk-FMOYUYH2.js";
|
|
14
|
+
import "./chunk-4FOHZ7JG.js";
|
|
15
15
|
import "./chunk-VY4Y5U57.js";
|
|
16
16
|
import "./chunk-MLKGABMK.js";
|
|
17
17
|
export {
|
package/package.json
CHANGED
package/runtime/lib/util.py
CHANGED
|
@@ -710,6 +710,60 @@ def invoke(tool, args, timeout=180):
|
|
|
710
710
|
return {'ok': False, 'error': r.stdout[:300], 'stderr': r.stderr[:300]}
|
|
711
711
|
|
|
712
712
|
|
|
713
|
+
def compact_error_text(value, depth=0):
|
|
714
|
+
if depth > 4 or value is None:
|
|
715
|
+
return ''
|
|
716
|
+
if isinstance(value, str):
|
|
717
|
+
return value
|
|
718
|
+
if isinstance(value, (int, float, bool)):
|
|
719
|
+
return str(value)
|
|
720
|
+
if isinstance(value, list):
|
|
721
|
+
return '\n'.join(compact_error_text(item, depth + 1) for item in value[:12])
|
|
722
|
+
if isinstance(value, dict):
|
|
723
|
+
parts = []
|
|
724
|
+
priority_keys = (
|
|
725
|
+
'error', 'message', 'script_error', 'stderr', 'stdout', 'raw',
|
|
726
|
+
'details', 'result', 'capture', 'proof', '_proof_json',
|
|
727
|
+
)
|
|
728
|
+
for key in priority_keys:
|
|
729
|
+
if key in value:
|
|
730
|
+
text = compact_error_text(value.get(key), depth + 1)
|
|
731
|
+
if text:
|
|
732
|
+
parts.append(text)
|
|
733
|
+
if not parts:
|
|
734
|
+
for item in list(value.values())[:12]:
|
|
735
|
+
text = compact_error_text(item, depth + 1)
|
|
736
|
+
if text:
|
|
737
|
+
parts.append(text)
|
|
738
|
+
return '\n'.join(parts)
|
|
739
|
+
return ''
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
def non_retryable_riddle_script_error(result):
|
|
743
|
+
text = compact_error_text(result).lower()
|
|
744
|
+
if not text:
|
|
745
|
+
return False
|
|
746
|
+
playwright_timeout = (
|
|
747
|
+
'timeout' in text
|
|
748
|
+
and (
|
|
749
|
+
'locator.' in text
|
|
750
|
+
or 'page.waitforurl' in text
|
|
751
|
+
or 'page.waitforselector' in text
|
|
752
|
+
or 'waiting for selector' in text
|
|
753
|
+
or 'waiting for navigation' in text
|
|
754
|
+
or 'getbyrole' in text
|
|
755
|
+
or 'getbytext' in text
|
|
756
|
+
or 'scrollintoviewifneeded' in text
|
|
757
|
+
)
|
|
758
|
+
)
|
|
759
|
+
deterministic_playwright_error = (
|
|
760
|
+
'strict mode violation' in text
|
|
761
|
+
or 'selector_not_found' in text
|
|
762
|
+
or 'index_out_of_range' in text
|
|
763
|
+
)
|
|
764
|
+
return playwright_timeout or deterministic_playwright_error
|
|
765
|
+
|
|
766
|
+
|
|
713
767
|
def invoke_retry(tool, args, retries=3, timeout=180):
|
|
714
768
|
"""Call an OpenClaw tool with automatic retries on failure."""
|
|
715
769
|
last_result = None
|
|
@@ -720,6 +774,9 @@ def invoke_retry(tool, args, retries=3, timeout=180):
|
|
|
720
774
|
if result.get('ok') or result.get('outputs') or result.get('screenshots'):
|
|
721
775
|
return result
|
|
722
776
|
print(f'invoke_retry({tool}) attempt {attempt}/{retries} failed: {str(result.get("error", "no output"))[:200]}')
|
|
777
|
+
if tool == 'riddle_script' and non_retryable_riddle_script_error(result):
|
|
778
|
+
print('invoke_retry(riddle_script) stopping early for deterministic Playwright script error')
|
|
779
|
+
return result
|
|
723
780
|
if attempt < retries:
|
|
724
781
|
import time
|
|
725
782
|
time.sleep(5)
|
package/runtime/lib/verify.py
CHANGED
|
@@ -1845,16 +1845,17 @@ def normalize_observed_path(value):
|
|
|
1845
1845
|
raw = str(value or '').strip()
|
|
1846
1846
|
if not raw:
|
|
1847
1847
|
return ''
|
|
1848
|
-
parsed = urlparse(raw
|
|
1848
|
+
parsed = urlparse(raw)
|
|
1849
1849
|
path = parsed.path or ''
|
|
1850
1850
|
query = parsed.query or ''
|
|
1851
|
+
fragment = parsed.fragment or ''
|
|
1851
1852
|
if not path.startswith('/'):
|
|
1852
1853
|
path = '/' + path.lstrip('/')
|
|
1853
1854
|
parts = path.split('/')
|
|
1854
1855
|
if len(parts) >= 4 and parts[1] == 's':
|
|
1855
1856
|
path = '/' + '/'.join(parts[3:])
|
|
1856
1857
|
path = path.rstrip('/') or '/'
|
|
1857
|
-
return path + (('?' + query) if query else '')
|
|
1858
|
+
return path + (('?' + query) if query else '') + (('#' + fragment) if fragment else '')
|
|
1858
1859
|
|
|
1859
1860
|
|
|
1860
1861
|
def observed_location_from_page_state(page_state):
|
|
@@ -1862,10 +1863,13 @@ def observed_location_from_page_state(page_state):
|
|
|
1862
1863
|
return ''
|
|
1863
1864
|
pathname = str(page_state.get('pathname') or '').strip()
|
|
1864
1865
|
search = str(page_state.get('search') or '').strip()
|
|
1866
|
+
hash_value = str(page_state.get('hash') or page_state.get('fragment') or '').strip()
|
|
1865
1867
|
if search and not search.startswith('?'):
|
|
1866
1868
|
search = '?' + search
|
|
1869
|
+
if hash_value and not hash_value.startswith('#'):
|
|
1870
|
+
hash_value = '#' + hash_value
|
|
1867
1871
|
if pathname:
|
|
1868
|
-
return pathname + search
|
|
1872
|
+
return pathname + search + hash_value
|
|
1869
1873
|
return str(page_state.get('href') or '').strip()
|
|
1870
1874
|
|
|
1871
1875
|
|
|
@@ -1889,9 +1893,29 @@ def route_matches_expected(expected_path, observed_path):
|
|
|
1889
1893
|
if pair not in remaining:
|
|
1890
1894
|
return False
|
|
1891
1895
|
remaining.remove(pair)
|
|
1896
|
+
if expected_parsed.fragment and observed_parsed.fragment != expected_parsed.fragment:
|
|
1897
|
+
return False
|
|
1892
1898
|
return True
|
|
1893
1899
|
|
|
1894
1900
|
|
|
1901
|
+
def route_parts(value):
|
|
1902
|
+
normalized = normalize_observed_path(value)
|
|
1903
|
+
if not normalized:
|
|
1904
|
+
return {
|
|
1905
|
+
'href': '',
|
|
1906
|
+
'pathname': '',
|
|
1907
|
+
'query': '',
|
|
1908
|
+
'hash': '',
|
|
1909
|
+
}
|
|
1910
|
+
parsed = urlparse(normalized)
|
|
1911
|
+
return {
|
|
1912
|
+
'href': normalized,
|
|
1913
|
+
'pathname': parsed.path.rstrip('/') or '/',
|
|
1914
|
+
'query': parsed.query or '',
|
|
1915
|
+
'hash': ('#' + parsed.fragment) if parsed.fragment else '',
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
|
|
1895
1919
|
EXPLICIT_TERMINAL_PATH_KEYS = (
|
|
1896
1920
|
'expected_terminal_path', 'expectedTerminalPath',
|
|
1897
1921
|
'expected_terminal_route', 'expectedTerminalRoute',
|
|
@@ -1980,6 +2004,16 @@ def terminal_path_from_record(record, depth=0):
|
|
|
1980
2004
|
return ''
|
|
1981
2005
|
|
|
1982
2006
|
|
|
2007
|
+
def terminal_path_from_text(value):
|
|
2008
|
+
if not isinstance(value, str):
|
|
2009
|
+
return ''
|
|
2010
|
+
for match in re.findall(r"""['"`](/[^'"`\s]+[?#][^'"`\s]*)['"`]""", value):
|
|
2011
|
+
candidate = path_candidate(match)
|
|
2012
|
+
if candidate:
|
|
2013
|
+
return candidate
|
|
2014
|
+
return ''
|
|
2015
|
+
|
|
2016
|
+
|
|
1983
2017
|
def interaction_assertions_pass(value):
|
|
1984
2018
|
for record in proof_evidence_records(value):
|
|
1985
2019
|
if any(record.get(key) is False for key in (
|
|
@@ -2039,29 +2073,58 @@ def interaction_terminal_path_from_state(state):
|
|
|
2039
2073
|
candidate = terminal_path_from_record(state.get(key))
|
|
2040
2074
|
if candidate:
|
|
2041
2075
|
return candidate, key
|
|
2076
|
+
for key in (
|
|
2077
|
+
'expected_terminal_path',
|
|
2078
|
+
'expected_after_path',
|
|
2079
|
+
'capture_script',
|
|
2080
|
+
'proof_plan',
|
|
2081
|
+
'success_criteria',
|
|
2082
|
+
'change_request',
|
|
2083
|
+
):
|
|
2084
|
+
candidate = path_candidate(state.get(key)) or terminal_path_from_text(state.get(key))
|
|
2085
|
+
if candidate:
|
|
2086
|
+
return candidate, key
|
|
2042
2087
|
return '', ''
|
|
2043
2088
|
|
|
2044
2089
|
|
|
2045
2090
|
def expected_path_for_verify(state, start_path, proof_evidence):
|
|
2046
2091
|
mode = normalized_verification_mode(state.get('verification_mode'))
|
|
2047
2092
|
normalized_start = normalize_observed_path(start_path) or '/'
|
|
2093
|
+
start_parts = route_parts(normalized_start)
|
|
2048
2094
|
if mode not in INTERACTION_MODES:
|
|
2049
2095
|
return normalized_start, {
|
|
2050
2096
|
'mode': mode,
|
|
2051
2097
|
'source': 'recon_start_path',
|
|
2052
2098
|
'start_path': normalized_start,
|
|
2053
2099
|
'expected_path': normalized_start,
|
|
2100
|
+
'start_pathname': start_parts['pathname'],
|
|
2101
|
+
'start_query': start_parts['query'],
|
|
2102
|
+
'start_hash': start_parts['hash'],
|
|
2103
|
+
'expected_pathname': start_parts['pathname'],
|
|
2104
|
+
'expected_query': start_parts['query'],
|
|
2105
|
+
'expected_hash': start_parts['hash'],
|
|
2054
2106
|
}
|
|
2055
2107
|
candidate, source = interaction_terminal_path_from_state(state)
|
|
2056
2108
|
if not candidate:
|
|
2057
2109
|
candidate, source = interaction_terminal_path_from_evidence(proof_evidence)
|
|
2058
2110
|
expected = candidate or normalized_start
|
|
2111
|
+
expected_parts = route_parts(expected)
|
|
2059
2112
|
return expected, {
|
|
2060
2113
|
'mode': mode,
|
|
2061
2114
|
'source': source or 'recon_start_path',
|
|
2062
2115
|
'start_path': normalized_start,
|
|
2063
2116
|
'expected_path': expected,
|
|
2064
2117
|
'terminal_path': expected if expected != normalized_start else '',
|
|
2118
|
+
'start_pathname': start_parts['pathname'],
|
|
2119
|
+
'start_query': start_parts['query'],
|
|
2120
|
+
'start_hash': start_parts['hash'],
|
|
2121
|
+
'expected_href': expected_parts['href'],
|
|
2122
|
+
'expected_pathname': expected_parts['pathname'],
|
|
2123
|
+
'expected_query': expected_parts['query'],
|
|
2124
|
+
'expected_hash': expected_parts['hash'],
|
|
2125
|
+
'terminal_pathname': expected_parts['pathname'] if expected != normalized_start else '',
|
|
2126
|
+
'terminal_query': expected_parts['query'] if expected != normalized_start else '',
|
|
2127
|
+
'terminal_hash': expected_parts['hash'] if expected != normalized_start else '',
|
|
2065
2128
|
}
|
|
2066
2129
|
|
|
2067
2130
|
|
|
@@ -2391,6 +2454,19 @@ def build_capture_retry_decision(after_observation, required_baseline_present, p
|
|
|
2391
2454
|
'reasons': reasons,
|
|
2392
2455
|
}
|
|
2393
2456
|
|
|
2457
|
+
details = after_observation.get('details') if isinstance(after_observation.get('details'), dict) else {}
|
|
2458
|
+
route_mismatch = None
|
|
2459
|
+
reason_text = str(after_observation.get('reason') or '')
|
|
2460
|
+
if 'wrong route' in reason_text:
|
|
2461
|
+
expected = details.get('expected_path') or ''
|
|
2462
|
+
observed = details.get('observed_path_raw') or details.get('observed_path') or ''
|
|
2463
|
+
if expected or observed:
|
|
2464
|
+
route_mismatch = {
|
|
2465
|
+
'field': 'route',
|
|
2466
|
+
'expected_path': expected,
|
|
2467
|
+
'observed_after_path': observed,
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2394
2470
|
if proof_evidence_blocker:
|
|
2395
2471
|
reasons.append(proof_evidence_blocker)
|
|
2396
2472
|
decision = 'missing_proof_evidence'
|
|
@@ -2399,19 +2475,36 @@ def build_capture_retry_decision(after_observation, required_baseline_present, p
|
|
|
2399
2475
|
reasons.append('The capture reached usable page context, but the proof evidence explicitly failed its own required audio gate.')
|
|
2400
2476
|
else:
|
|
2401
2477
|
reasons.append('The capture reached usable page context, but the proof script did not emit the structured evidence required for this verification mode.')
|
|
2478
|
+
if route_mismatch:
|
|
2479
|
+
reasons.append(
|
|
2480
|
+
'Route mismatch also present: expected after capture path ' +
|
|
2481
|
+
(route_mismatch.get('expected_path') or '(unknown)') +
|
|
2482
|
+
', observed ' +
|
|
2483
|
+
(route_mismatch.get('observed_after_path') or '(unknown)') +
|
|
2484
|
+
'.'
|
|
2485
|
+
)
|
|
2402
2486
|
reasons.append('Return to author so the capture script can expose passing proof evidence before verify asks for a supervising-agent judgment.')
|
|
2487
|
+
summary = proof_evidence_blocker
|
|
2488
|
+
if route_mismatch:
|
|
2489
|
+
summary += (
|
|
2490
|
+
' Route mismatch: expected ' +
|
|
2491
|
+
(route_mismatch.get('expected_path') or '(unknown)') +
|
|
2492
|
+
', got ' +
|
|
2493
|
+
(route_mismatch.get('observed_after_path') or '(unknown)') +
|
|
2494
|
+
'.'
|
|
2495
|
+
)
|
|
2403
2496
|
return {
|
|
2404
2497
|
'decision': decision,
|
|
2405
|
-
'summary':
|
|
2498
|
+
'summary': summary,
|
|
2406
2499
|
'recommended_stage': 'author',
|
|
2407
2500
|
'continue_with_stage': 'author',
|
|
2408
2501
|
'reasons': reasons,
|
|
2502
|
+
'mismatch': route_mismatch,
|
|
2409
2503
|
}
|
|
2410
2504
|
|
|
2411
2505
|
reason = after_observation.get('reason') or 'after capture is not usable yet'
|
|
2412
2506
|
reasons.append('The after evidence is not usable yet: ' + reason)
|
|
2413
2507
|
recommended_stage = 'recon' if 'wrong route' in reason else 'author'
|
|
2414
|
-
details = after_observation.get('details') if isinstance(after_observation.get('details'), dict) else {}
|
|
2415
2508
|
error_messages = [
|
|
2416
2509
|
str(item).strip()
|
|
2417
2510
|
for item in (details.get('capture_error_messages') or [])
|
|
@@ -2528,6 +2621,9 @@ def build_semantic_context(state, results, after_observation, expected_path):
|
|
|
2528
2621
|
after_semantic = semantic_observation('after', after_observation)
|
|
2529
2622
|
expected_start_path = state.get('expected_start_path') or expected_path
|
|
2530
2623
|
route_expectation = state.get('route_expectation') if isinstance(state.get('route_expectation'), dict) else {}
|
|
2624
|
+
expected_parts = route_parts(expected_path)
|
|
2625
|
+
start_parts = route_parts(expected_start_path)
|
|
2626
|
+
after_parts = route_parts(after_semantic.get('observed_path_raw') or after_semantic.get('observed_path') or '')
|
|
2531
2627
|
return {
|
|
2532
2628
|
'expected_path': expected_path,
|
|
2533
2629
|
'expected_start_path': expected_start_path,
|
|
@@ -2540,10 +2636,20 @@ def build_semantic_context(state, results, after_observation, expected_path):
|
|
|
2540
2636
|
'expected_after_path': expected_path,
|
|
2541
2637
|
'expected_start_path': expected_start_path,
|
|
2542
2638
|
'expected_terminal_path': route_expectation.get('terminal_path') or '',
|
|
2639
|
+
'expected_pathname': expected_parts['pathname'],
|
|
2640
|
+
'expected_query': expected_parts['query'],
|
|
2641
|
+
'expected_hash': expected_parts['hash'],
|
|
2642
|
+
'expected_start_pathname': start_parts['pathname'],
|
|
2643
|
+
'expected_start_query': start_parts['query'],
|
|
2644
|
+
'expected_start_hash': start_parts['hash'],
|
|
2645
|
+
'expected_terminal_query': route_expectation.get('terminal_query') or route_expectation.get('expected_query') or '',
|
|
2646
|
+
'expected_terminal_hash': route_expectation.get('terminal_hash') or route_expectation.get('expected_hash') or '',
|
|
2543
2647
|
'expectation_source': route_expectation.get('source') or '',
|
|
2544
2648
|
'before_observed_path': before_semantic.get('observed_path') or before.get('path') or '',
|
|
2545
2649
|
'prod_observed_path': prod_semantic.get('observed_path') or prod.get('path') or '',
|
|
2546
2650
|
'after_observed_path': after_semantic.get('observed_path') or '',
|
|
2651
|
+
'after_observed_query': after_parts['query'],
|
|
2652
|
+
'after_observed_hash': after_parts['hash'],
|
|
2547
2653
|
},
|
|
2548
2654
|
'before': before_semantic,
|
|
2549
2655
|
'prod': prod_semantic,
|
|
@@ -3051,6 +3157,15 @@ if expected_start_path and expected_start_path != expected_path:
|
|
|
3051
3157
|
summary_lines.append('Expected terminal proof path: ' + expected_path)
|
|
3052
3158
|
else:
|
|
3053
3159
|
summary_lines.append('Expected proof path from recon: ' + expected_path)
|
|
3160
|
+
route_expected_query = (s.get('route_expectation') or {}).get('expected_query') or ''
|
|
3161
|
+
route_expected_hash = (s.get('route_expectation') or {}).get('expected_hash') or ''
|
|
3162
|
+
if route_expected_query or route_expected_hash:
|
|
3163
|
+
summary_lines.append(
|
|
3164
|
+
'Expected terminal query/hash: ' +
|
|
3165
|
+
('?' + route_expected_query if route_expected_query else '(none)') +
|
|
3166
|
+
' ' +
|
|
3167
|
+
(route_expected_hash if route_expected_hash else '(none)')
|
|
3168
|
+
)
|
|
3054
3169
|
summary_lines.append('After observation: ' + after_observation['reason'])
|
|
3055
3170
|
supporting = results['after'].get('supporting_artifacts') or {}
|
|
3056
3171
|
if supporting.get('has_structured_payload'):
|
|
@@ -3064,6 +3179,14 @@ if supporting.get('has_structured_payload'):
|
|
|
3064
3179
|
summary_lines.append('Structured after evidence: ' + ('; '.join(basis) if basis else 'present'))
|
|
3065
3180
|
observed_path = (after_observation.get('details') or {}).get('observed_path') or expected_path
|
|
3066
3181
|
summary_lines.append('Observed after path: ' + observed_path)
|
|
3182
|
+
observed_parts = route_parts((after_observation.get('details') or {}).get('observed_path_raw') or observed_path)
|
|
3183
|
+
if observed_parts.get('query') or observed_parts.get('hash') or route_expected_query or route_expected_hash:
|
|
3184
|
+
summary_lines.append(
|
|
3185
|
+
'Observed after query/hash: ' +
|
|
3186
|
+
('?' + observed_parts.get('query') if observed_parts.get('query') else '(none)') +
|
|
3187
|
+
' ' +
|
|
3188
|
+
(observed_parts.get('hash') if observed_parts.get('hash') else '(none)')
|
|
3189
|
+
)
|
|
3067
3190
|
details = after_observation.get('details') or {}
|
|
3068
3191
|
if details.get('headings'):
|
|
3069
3192
|
summary_lines.append('Visible headings: ' + '; '.join(str(item) for item in details.get('headings', [])[:6]))
|
|
@@ -24,5 +24,6 @@ steps:
|
|
|
24
24
|
|
|
25
25
|
- id: run_author
|
|
26
26
|
command: |
|
|
27
|
-
|
|
27
|
+
: "${RIDDLE_PROOF_DIR:?RIDDLE_PROOF_DIR must point to the @riddledc/riddle-proof/runtime directory}"
|
|
28
|
+
RP="$RIDDLE_PROOF_DIR"
|
|
28
29
|
python3 "${RP}/lib/author.py"
|
|
@@ -22,5 +22,6 @@ steps:
|
|
|
22
22
|
|
|
23
23
|
- id: run_implement
|
|
24
24
|
command: |
|
|
25
|
-
|
|
25
|
+
: "${RIDDLE_PROOF_DIR:?RIDDLE_PROOF_DIR must point to the @riddledc/riddle-proof/runtime directory}"
|
|
26
|
+
RP="$RIDDLE_PROOF_DIR"
|
|
26
27
|
python3 "${RP}/lib/implement.py"
|
|
@@ -30,7 +30,8 @@ steps:
|
|
|
30
30
|
|
|
31
31
|
- id: run_recon
|
|
32
32
|
command: |
|
|
33
|
-
|
|
33
|
+
: "${RIDDLE_PROOF_DIR:?RIDDLE_PROOF_DIR must point to the @riddledc/riddle-proof/runtime directory}"
|
|
34
|
+
RP="$RIDDLE_PROOF_DIR"
|
|
34
35
|
python3 "${RP}/lib/recon.py"
|
|
35
36
|
|
|
36
37
|
- id: summarize_recon
|
|
@@ -148,10 +148,12 @@ steps:
|
|
|
148
148
|
with open(args_file, 'w') as f:
|
|
149
149
|
json.dump(args, f, indent=2)
|
|
150
150
|
PYEOF
|
|
151
|
-
|
|
151
|
+
: "${RIDDLE_PROOF_DIR:?RIDDLE_PROOF_DIR must point to the @riddledc/riddle-proof/runtime directory}"
|
|
152
|
+
RP="$RIDDLE_PROOF_DIR"
|
|
152
153
|
python3 "${RP}/lib/preflight.py"
|
|
153
154
|
|
|
154
155
|
- id: setup
|
|
155
156
|
command: |
|
|
156
|
-
|
|
157
|
+
: "${RIDDLE_PROOF_DIR:?RIDDLE_PROOF_DIR must point to the @riddledc/riddle-proof/runtime directory}"
|
|
158
|
+
RP="$RIDDLE_PROOF_DIR"
|
|
157
159
|
python3 "${RP}/lib/setup.py"
|
|
@@ -32,5 +32,6 @@ steps:
|
|
|
32
32
|
|
|
33
33
|
- id: ship
|
|
34
34
|
command: |
|
|
35
|
-
|
|
35
|
+
: "${RIDDLE_PROOF_DIR:?RIDDLE_PROOF_DIR must point to the @riddledc/riddle-proof/runtime directory}"
|
|
36
|
+
RP="$RIDDLE_PROOF_DIR"
|
|
36
37
|
python3 "${RP}/lib/ship.py"
|
|
@@ -54,7 +54,8 @@ steps:
|
|
|
54
54
|
|
|
55
55
|
- id: run_verify
|
|
56
56
|
command: |
|
|
57
|
-
|
|
57
|
+
: "${RIDDLE_PROOF_DIR:?RIDDLE_PROOF_DIR must point to the @riddledc/riddle-proof/runtime directory}"
|
|
58
|
+
RP="$RIDDLE_PROOF_DIR"
|
|
58
59
|
python3 "${RP}/lib/verify.py"
|
|
59
60
|
|
|
60
61
|
- id: present_evidence
|