harness-everything 0.47.1 → 0.47.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.github/workflows/ci.yml +12 -0
- package/CHANGELOG.md +9 -0
- package/benchmarks/issue290-pilot/README.md +199 -0
- package/benchmarks/issue290-pilot/analyze.py +299 -0
- package/benchmarks/issue290-pilot/analyze.test.py +146 -0
- package/benchmarks/issue290-pilot/check.py +19 -0
- package/benchmarks/issue290-pilot/evidence/archive.json +7 -0
- package/benchmarks/issue290-pilot/evidence/group-summary.json +684 -0
- package/benchmarks/issue290-pilot/evidence/inventory.json +3728 -0
- package/benchmarks/issue290-pilot/evidence/ledger.json +4644 -0
- package/benchmarks/issue290-pilot/evidence/replay/pairs.json +482 -0
- package/benchmarks/issue290-pilot/evidence/replay/provenance.json +24 -0
- package/benchmarks/issue290-pilot/evidence/replay/tables.md +37 -0
- package/benchmarks/issue290-pilot/evidence.tar.gz +0 -0
- package/benchmarks/issue290-pilot/export.py +110 -0
- package/benchmarks/issue290-pilot/export.test.py +65 -0
- package/benchmarks/issue290-pilot/fable-supplement.py +55 -0
- package/benchmarks/issue290-pilot/fixture.test.py +28 -0
- package/benchmarks/issue290-pilot/fixtures/polyglot/instructions.md +19 -0
- package/benchmarks/issue290-pilot/fixtures/polyglot/package.json +29 -0
- package/benchmarks/issue290-pilot/fixtures/polyglot/simple-linked-list.js +44 -0
- package/benchmarks/issue290-pilot/fixtures/polyglot/simple-linked-list.spec.js +131 -0
- package/benchmarks/issue290-pilot/fixtures/quixbugs/LICENSE +7 -0
- package/benchmarks/issue290-pilot/fixtures/quixbugs/cases.json +7 -0
- package/benchmarks/issue290-pilot/fixtures/quixbugs/find_in_sorted.py +31 -0
- package/benchmarks/issue290-pilot/fixtures/quixbugs/test_find_in_sorted.py +15 -0
- package/benchmarks/issue290-pilot/frozen-documents.json +41 -0
- package/benchmarks/issue290-pilot/grader.cjs +43 -0
- package/benchmarks/issue290-pilot/grader.test.cjs +10 -0
- package/benchmarks/issue290-pilot/hook.test.cjs +27 -0
- package/benchmarks/issue290-pilot/host-hook.cjs +35 -0
- package/benchmarks/issue290-pilot/metrics.test.py +131 -0
- package/benchmarks/issue290-pilot/preflight/amendment.md +32 -0
- package/benchmarks/issue290-pilot/preflight/environment.json +15 -0
- package/benchmarks/issue290-pilot/preflight/fable-amendment.md +20 -0
- package/benchmarks/issue290-pilot/preflight/fable-frozen-files.json +4 -0
- package/benchmarks/issue290-pilot/preflight/fable-infrastructure-amendment.md +27 -0
- package/benchmarks/issue290-pilot/preflight/fable-retry-frozen-files.json +4 -0
- package/benchmarks/issue290-pilot/preflight/fable-supplement-v1.py +47 -0
- package/benchmarks/issue290-pilot/preflight/frozen-files.json +18 -0
- package/benchmarks/issue290-pilot/preflight/graders.json +67 -0
- package/benchmarks/issue290-pilot/pricing-assumptions.json +29 -0
- package/benchmarks/issue290-pilot/protocol.json +32 -0
- package/benchmarks/issue290-pilot/read_metrics.py +166 -0
- package/benchmarks/issue290-pilot/replay.py +167 -0
- package/benchmarks/issue290-pilot/reporting.py +82 -0
- package/benchmarks/issue290-pilot/run.py +262 -0
- package/benchmarks/issue290-pilot/sources.json +10 -0
- package/benchmarks/issue290-pilot/verification/analyzer-tests.log +5 -0
- package/benchmarks/issue290-pilot/verification/final-gates.json +58 -0
- package/benchmarks/issue290-pilot/verification/fixture-tests.log +5 -0
- package/benchmarks/issue290-pilot/verification/gates.json +58 -0
- package/benchmarks/issue290-pilot/verification/npm-audit.json +84 -0
- package/benchmarks/issue290-pilot/verification/offline-correction.json +59 -0
- package/benchmarks/issue290-pilot/verification/post-report/helper-tests.log +22 -0
- package/benchmarks/issue290-pilot/verification/post-report/test-consistency.log +626 -0
- package/benchmarks/issue290-pilot/verification/post-report/test-references.log +6 -0
- package/benchmarks/issue290-pilot/verification/post-report/waza-tokens.log +710 -0
- package/benchmarks/issue290-pilot/verification/test-collision.log +28 -0
- package/benchmarks/issue290-pilot/verification/test-consistency.log +28 -0
- package/benchmarks/issue290-pilot/verification/test-docs-capabilities.log +131 -0
- package/benchmarks/issue290-pilot/verification/test-mechanism.log +1829 -0
- package/benchmarks/issue290-pilot/verification/test-mutations.log +16 -0
- package/benchmarks/issue290-pilot/verification/test-platform-compatibility.log +9 -0
- package/benchmarks/issue290-pilot/verification/test-plugin-openai.log +6 -0
- package/benchmarks/issue290-pilot/verification/test-plugin-submission.log +5 -0
- package/benchmarks/issue290-pilot/verification/test-references.log +6 -0
- package/benchmarks/issue290-pilot/verification/test-release.log +59 -0
- package/benchmarks/issue290-pilot/verification/test-repo-contract.log +5 -0
- package/benchmarks/issue290-pilot/verification/test-routing-invariants.log +785 -0
- package/benchmarks/issue290-pilot/verification/test-routing-skills.log +28 -0
- package/benchmarks/issue290-pilot/verification/test.log +3373 -0
- package/benchmarks/issue290-pilot/verification/verification-report.md +76 -0
- package/benchmarks/issue290-pilot/verification/waza-tokens.log +710 -0
- package/benchmarks/issue290-pilot/verification/with-dependencies/gates.json +26 -0
- package/benchmarks/issue290-pilot/verification/with-dependencies/test-collision.log +8 -0
- package/benchmarks/issue290-pilot/verification/with-dependencies/test-consistency.log +626 -0
- package/benchmarks/issue290-pilot/verification/with-dependencies/test-mechanism.log +1693 -0
- package/benchmarks/issue290-pilot/verification/with-dependencies/test-release.log +38 -0
- package/benchmarks/issue290-pilot/verification/with-dependencies/test-routing-skills.log +44 -0
- package/benchmarks/issue290-pilot/verification/with-dependencies/test.log +3253 -0
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/plugin.json +1 -1
- package/sbom.cdx.json +7 -7
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""Shared, conservative reference attribution; never execute captured commands.
|
|
2
|
+
|
|
3
|
+
Filesystem access, mixed shell output and identified reference content are
|
|
4
|
+
different metrics. Only paths in the episode's declared document bundle count.
|
|
5
|
+
Unknown transformations remain uncertain, rather than being counted as reads.
|
|
6
|
+
"""
|
|
7
|
+
import hashlib
|
|
8
|
+
import re
|
|
9
|
+
import shlex
|
|
10
|
+
|
|
11
|
+
READERS = {'cat', 'sed', 'head', 'tail', 'rg', 'grep', 'get-content', 'gc', 'type'}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def segments(command):
|
|
15
|
+
if not isinstance(command, str):
|
|
16
|
+
return []
|
|
17
|
+
try:
|
|
18
|
+
# Preserve backslashes in PowerShell paths. Quoted shell wrappers are
|
|
19
|
+
# unwrapped before this lexer is used for their actual program.
|
|
20
|
+
command = command.replace('<HARNESS_SOURCE>', '__HARNESS_SOURCE__').replace('<TMP>', '__TMP__')
|
|
21
|
+
lexer = shlex.shlex(command, posix=True, punctuation_chars=';&|()<>')
|
|
22
|
+
lexer.escape = ''
|
|
23
|
+
lexer.whitespace_split = True
|
|
24
|
+
tokens = [token.replace('__HARNESS_SOURCE__', '<HARNESS_SOURCE>').replace('__TMP__', '<TMP>') for token in lexer]
|
|
25
|
+
except (ValueError, TypeError):
|
|
26
|
+
return []
|
|
27
|
+
if tokens and tokens[0].rsplit('/', 1)[-1] in ('sh', 'bash', 'zsh') and len(tokens) == 3 and tokens[1] in ('-c', '-lc'):
|
|
28
|
+
return segments(tokens[2])
|
|
29
|
+
result, current = [], []
|
|
30
|
+
for token in tokens:
|
|
31
|
+
if token and all(c in ';&|()<>' for c in token):
|
|
32
|
+
if current:
|
|
33
|
+
result.append(current)
|
|
34
|
+
current = []
|
|
35
|
+
else:
|
|
36
|
+
current.append(token)
|
|
37
|
+
if current:
|
|
38
|
+
result.append(current)
|
|
39
|
+
return result
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def is_content_command(command):
|
|
43
|
+
return any(part and part[0].lower().rsplit('/', 1)[-1] in READERS
|
|
44
|
+
and not (part[0].lower() == 'rg' and '--files' in part)
|
|
45
|
+
for part in segments(command))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def reference_path(value, documents, source=''):
|
|
49
|
+
value = str(value).replace('\\', '/').removeprefix('./')
|
|
50
|
+
for prefix in ('.harness/', '<HARNESS_SOURCE>/', source.rstrip('/') + '/' if source else ''):
|
|
51
|
+
if prefix and value.startswith(prefix):
|
|
52
|
+
relative = value[len(prefix):]
|
|
53
|
+
return relative if relative in documents else None
|
|
54
|
+
# Native Read can supply an absolute workspace/.harness path.
|
|
55
|
+
if '/.harness/' in value:
|
|
56
|
+
relative = value.split('/.harness/', 1)[1]
|
|
57
|
+
return relative if relative in documents else None
|
|
58
|
+
return value if value in documents else None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def observed_read(command, output, documents, source='', native_path=None):
|
|
62
|
+
paths = []
|
|
63
|
+
if native_path is not None:
|
|
64
|
+
relative = reference_path(native_path, documents, source)
|
|
65
|
+
if relative:
|
|
66
|
+
paths.append(relative)
|
|
67
|
+
else:
|
|
68
|
+
for part in segments(command):
|
|
69
|
+
if not part or not is_content_command(shlex.join(part)):
|
|
70
|
+
continue
|
|
71
|
+
for token in part[1:]:
|
|
72
|
+
relative = reference_path(token, documents, source)
|
|
73
|
+
if relative and relative not in paths:
|
|
74
|
+
paths.append(relative)
|
|
75
|
+
if not paths:
|
|
76
|
+
return None
|
|
77
|
+
remaining = output or ''
|
|
78
|
+
matched = []
|
|
79
|
+
# Match complete line runs or complete files. A numeric wc result, a
|
|
80
|
+
# filename listing, or prose mentioning a path does not identify content.
|
|
81
|
+
# Very short isolated fragments stay uncertain to avoid incidental matches.
|
|
82
|
+
for relative in paths:
|
|
83
|
+
content = documents[relative]
|
|
84
|
+
if not content:
|
|
85
|
+
continue
|
|
86
|
+
if content in remaining:
|
|
87
|
+
remaining = remaining.replace(content, '', 1)
|
|
88
|
+
matched.append({'path': relative, 'bytes': len(content.encode()), 'kind': 'full-file'})
|
|
89
|
+
continue
|
|
90
|
+
lines = remaining.splitlines(keepends=True)
|
|
91
|
+
index = 0
|
|
92
|
+
while index < len(lines):
|
|
93
|
+
end = index + 1
|
|
94
|
+
best = None
|
|
95
|
+
while end <= len(lines):
|
|
96
|
+
fragment = ''.join(lines[index:end])
|
|
97
|
+
if fragment not in content:
|
|
98
|
+
break
|
|
99
|
+
if len(fragment.strip()) >= 32:
|
|
100
|
+
best = (end, fragment)
|
|
101
|
+
end += 1
|
|
102
|
+
if best:
|
|
103
|
+
end, fragment = best
|
|
104
|
+
matched.append({'path': relative, 'bytes': len(fragment.encode()), 'kind': 'partial-content'})
|
|
105
|
+
remaining = remaining.replace(fragment, '', 1)
|
|
106
|
+
index = end
|
|
107
|
+
else:
|
|
108
|
+
index += 1
|
|
109
|
+
attributable = sum(item['bytes'] for item in matched)
|
|
110
|
+
total = len((output or '').encode())
|
|
111
|
+
return {'command': command, 'paths': paths, 'filesystem_access_candidates': len(paths),
|
|
112
|
+
'shell_output_bytes': total, 'returned_bytes': attributable,
|
|
113
|
+
'exact_reference_bytes': attributable,
|
|
114
|
+
'uncertain_or_mixed_output_bytes': total - attributable,
|
|
115
|
+
'matched_content': matched,
|
|
116
|
+
'content_sha256': hashlib.sha256((output or '').encode()).hexdigest(),
|
|
117
|
+
'evidence': 'content match against frozen declared bundle; access alone is not returned content'}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def collect_reads(events, documents, source=''):
|
|
121
|
+
reads, commands, errors = [], [], []
|
|
122
|
+
tools = {tool['id']: tool for event in events
|
|
123
|
+
for tool in event.get('message', {}).get('content', [])
|
|
124
|
+
if isinstance(tool, dict) and tool.get('type') == 'tool_use' and tool.get('id')}
|
|
125
|
+
active = 'uncomposed'
|
|
126
|
+
for event in events:
|
|
127
|
+
outputs = []
|
|
128
|
+
item = event.get('item', {})
|
|
129
|
+
if event.get('type') == 'item.completed' and item.get('type') == 'command_execution':
|
|
130
|
+
outputs.append((item.get('command', ''), item.get('aggregated_output', '')))
|
|
131
|
+
if item.get('exit_code') not in (0, None):
|
|
132
|
+
errors.append({'command': item.get('command'), 'exit': item.get('exit_code')})
|
|
133
|
+
result = event.get('tool_use_result')
|
|
134
|
+
if isinstance(result, dict):
|
|
135
|
+
if result.get('type') == 'text' and isinstance(result.get('file'), dict):
|
|
136
|
+
file = result['file']
|
|
137
|
+
read = observed_read('', file.get('content', ''), documents, source, file.get('filePath', ''))
|
|
138
|
+
if read:
|
|
139
|
+
reads.append({'active_step': active, **read})
|
|
140
|
+
if 'stdout' in result:
|
|
141
|
+
command = ''
|
|
142
|
+
for tool in event.get('message', {}).get('content', []):
|
|
143
|
+
if isinstance(tool, dict) and tool.get('type') == 'tool_result':
|
|
144
|
+
command = tools.get(tool.get('tool_use_id'), {}).get('input', {}).get('command', '')
|
|
145
|
+
outputs.append((command, result.get('stdout', '')))
|
|
146
|
+
if result.get('interrupted'):
|
|
147
|
+
errors.append({'command': command, 'interrupted': True})
|
|
148
|
+
elif isinstance(result, str) and result.startswith('Error:'):
|
|
149
|
+
errors.append({'tool_error': result})
|
|
150
|
+
for command, output in outputs:
|
|
151
|
+
commands.append(command)
|
|
152
|
+
if 'workflow-disposition.js' in command:
|
|
153
|
+
import json
|
|
154
|
+
try:
|
|
155
|
+
data, _ = json.JSONDecoder().raw_decode(output.lstrip())
|
|
156
|
+
if isinstance(data, dict):
|
|
157
|
+
if data.get('activeStep'):
|
|
158
|
+
active = data['activeStep']['id']
|
|
159
|
+
elif data.get('activeStages'):
|
|
160
|
+
active = ','.join(stage.get('stageId', '?') for stage in data['activeStages'])
|
|
161
|
+
except (ValueError, KeyError, TypeError):
|
|
162
|
+
pass
|
|
163
|
+
read = observed_read(command, output, documents, source)
|
|
164
|
+
if read:
|
|
165
|
+
reads.append({'active_step': active, **read})
|
|
166
|
+
return reads, commands, errors
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Rebuild pilot evidence offline, from hash-checked committed inputs only."""
|
|
3
|
+
import argparse
|
|
4
|
+
import hashlib
|
|
5
|
+
import importlib
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path, PurePosixPath
|
|
8
|
+
import tarfile
|
|
9
|
+
import tempfile
|
|
10
|
+
|
|
11
|
+
from analyze import inspect_episode
|
|
12
|
+
from reporting import paired_rows, report_tables, summarize_groups
|
|
13
|
+
|
|
14
|
+
HERE = Path(__file__).resolve().parent
|
|
15
|
+
exporter = importlib.import_module('export')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def key(row):
|
|
19
|
+
return (row['series'], row['model']['engine'], row['workload'], row['arm'], row['repeat'])
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def extract_verified(target):
|
|
23
|
+
inventory = json.loads((HERE/'evidence/inventory.json').read_text())
|
|
24
|
+
expected = {item['path']: item for item in inventory}
|
|
25
|
+
found = set()
|
|
26
|
+
with tarfile.open(HERE/'evidence.tar.gz') as archive:
|
|
27
|
+
for member in archive.getmembers():
|
|
28
|
+
parts = PurePosixPath(member.name).parts
|
|
29
|
+
if not parts or parts[0] != 'evidence' or '..' in parts or member.issym() or member.islnk():
|
|
30
|
+
raise ValueError('unsafe archive member')
|
|
31
|
+
if member.isdir():
|
|
32
|
+
continue
|
|
33
|
+
relative = '/'.join(parts[1:])
|
|
34
|
+
if relative == 'inventory.json':
|
|
35
|
+
continue
|
|
36
|
+
if not member.isfile() or relative not in expected or relative in found:
|
|
37
|
+
raise ValueError('unexpected/duplicate evidence file')
|
|
38
|
+
raw = archive.extractfile(member).read()
|
|
39
|
+
if hashlib.sha256(raw).hexdigest() != expected[relative]['exported_sha256']:
|
|
40
|
+
raise ValueError('exported evidence hash mismatch')
|
|
41
|
+
exporter.validate_no_secrets(raw.decode())
|
|
42
|
+
path = target/relative
|
|
43
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
44
|
+
path.write_bytes(raw)
|
|
45
|
+
found.add(relative)
|
|
46
|
+
if found != set(expected):
|
|
47
|
+
raise ValueError('missing exported evidence files')
|
|
48
|
+
return len(found)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def regenerate():
|
|
52
|
+
with tempfile.TemporaryDirectory(prefix='harness-pilot-replay-') as temporary:
|
|
53
|
+
root = Path(temporary)
|
|
54
|
+
count = extract_verified(root)
|
|
55
|
+
frozen_rows = json.loads((root/'issue290-final-audit/audited-rows.json').read_text())
|
|
56
|
+
frozen = {key(row): row for row in frozen_rows}
|
|
57
|
+
if len(frozen) != 40:
|
|
58
|
+
raise ValueError('frozen audit count/identity mismatch')
|
|
59
|
+
bundle = json.loads((HERE/'frozen-documents.json').read_text())
|
|
60
|
+
rows = []
|
|
61
|
+
for manifest_path in sorted(root.glob('*/*/manifest.json')):
|
|
62
|
+
episode = manifest_path.parent
|
|
63
|
+
manifest = json.loads(manifest_path.read_text())
|
|
64
|
+
identity = {**manifest, 'series': episode.parent.name}
|
|
65
|
+
documents = {}
|
|
66
|
+
for name, digest in manifest['documents'].items():
|
|
67
|
+
document = bundle['documents'][name]
|
|
68
|
+
if document['source_sha256'] != digest or hashlib.sha256(document['content'].encode()).hexdigest() != digest:
|
|
69
|
+
raise ValueError('document revision differs from episode manifest')
|
|
70
|
+
documents[name] = document['content']
|
|
71
|
+
# The live JS fixture declared ESM, but the original episode
|
|
72
|
+
# exporter retained only the implementation. Restore that pinned
|
|
73
|
+
# launch prerequisite instead of relying on host module detection.
|
|
74
|
+
if manifest['workload'] == 'polyglot-simple-linked-list-staged':
|
|
75
|
+
package = '{"type":"module"}\n'
|
|
76
|
+
if manifest['fixture'].get('package.json') != hashlib.sha256(package.encode()).hexdigest():
|
|
77
|
+
raise ValueError('unexpected module fixture identity')
|
|
78
|
+
(episode/'package.json').write_text(package)
|
|
79
|
+
row = inspect_episode(episode, offline=True, frozen=frozen[key(identity)], documents=documents)
|
|
80
|
+
row['series'] = episode.parent.name
|
|
81
|
+
# No host reasoning, assistant prose, dispatch arguments, or child
|
|
82
|
+
# transcripts are republished by the derived ledger.
|
|
83
|
+
keep = ('series', 'model', 'workload', 'arm', 'repeat', 'preflight', 'classification',
|
|
84
|
+
'wall_seconds', 'exit', 'stop_reason', 'budget_failure', 'cost_observability',
|
|
85
|
+
'api_equivalent_cost_usd', 'api_equivalent_input_cost_usd', 'parent_api_equivalent_cost_usd',
|
|
86
|
+
'reference_returned_bytes', 'exact_reference_bytes_lower_bound',
|
|
87
|
+
'reference_filesystem_access_candidates', 'reference_shell_output_bytes',
|
|
88
|
+
'uncertain_or_mixed_output_bytes', 'observed_reference_reads',
|
|
89
|
+
'effective_effort_reported', 'input_usage_reconciles', 'usage',
|
|
90
|
+
'child_usage_observability', 'strategies', 'tdd_quality_gate_name_matched_invocation',
|
|
91
|
+
'independent_grader', 'telemetry_provenance')
|
|
92
|
+
rows.append({name: row.get(name) for name in keep})
|
|
93
|
+
if len(rows) != 40 or {key(row) for row in rows} != set(frozen):
|
|
94
|
+
raise ValueError('replayed episode identities differ')
|
|
95
|
+
rows.sort(key=key)
|
|
96
|
+
pairs = paired_rows(rows)
|
|
97
|
+
output = {'ledger.json': rows, 'group-summary.json': summarize_groups(rows), 'pairs.json': pairs,
|
|
98
|
+
'provenance.json': {'verified_exported_files': count,
|
|
99
|
+
'archive_sha256': hashlib.sha256((HERE/'evidence.tar.gz').read_bytes()).hexdigest(),
|
|
100
|
+
'pricing_assumptions_sha256': hashlib.sha256((HERE/'pricing-assumptions.json').read_bytes()).hexdigest(),
|
|
101
|
+
'frozen_documents_sha256': hashlib.sha256((HERE/'frozen-documents.json').read_bytes()).hexdigest(),
|
|
102
|
+
'recomputed': ['parent-stream content attribution', 'artifact checks', 'gate-name invocation', 'metric denominators', 'paired deltas'],
|
|
103
|
+
'frozen_not_independently_recovered': ['request usage', 'child dispatch metadata', 'effort', 'usage aggregates'],
|
|
104
|
+
'irretrievable': ['unobserved worker usage/model identities', 'interrupted final usage'],
|
|
105
|
+
'unknown_policy': 'non-reconstructable whole-run costs remain null; no host-home reads or model calls'}}
|
|
106
|
+
result = {}
|
|
107
|
+
for name, value in output.items():
|
|
108
|
+
text = json.dumps(value, indent=2, ensure_ascii=False, sort_keys=True)+'\n'
|
|
109
|
+
text = text.replace(str(root), '<REPLAY_ROOT>').replace(str(HERE.parent.parent), '<HARNESS_SOURCE>')
|
|
110
|
+
exporter.validate_no_secrets(text)
|
|
111
|
+
result[name] = text
|
|
112
|
+
result['tables.md'] = report_tables(rows, pairs)
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def main():
|
|
117
|
+
parser = argparse.ArgumentParser()
|
|
118
|
+
parser.add_argument('--check', action='store_true', help='compare regenerated data with committed expected values')
|
|
119
|
+
args = parser.parse_args()
|
|
120
|
+
result = regenerate()
|
|
121
|
+
def destination(name):
|
|
122
|
+
return HERE/'evidence'/name if name in ('ledger.json', 'group-summary.json') else HERE/'evidence/replay'/name
|
|
123
|
+
if args.check:
|
|
124
|
+
for name, text in result.items():
|
|
125
|
+
if not destination(name).is_file() or destination(name).read_text() != text:
|
|
126
|
+
if name.endswith('.json') and destination(name).is_file():
|
|
127
|
+
def differences(expected, actual, path='$'):
|
|
128
|
+
if type(expected) is not type(actual):
|
|
129
|
+
yield path+' (type)'
|
|
130
|
+
elif isinstance(expected, dict):
|
|
131
|
+
for field in sorted(set(expected) | set(actual)):
|
|
132
|
+
if field not in expected or field not in actual:
|
|
133
|
+
yield path+'.'+field+' (missing)'
|
|
134
|
+
else:
|
|
135
|
+
yield from differences(expected[field], actual[field], path+'.'+field)
|
|
136
|
+
elif isinstance(expected, list):
|
|
137
|
+
if len(expected) != len(actual):
|
|
138
|
+
yield path+' (length)'
|
|
139
|
+
for index, (left, right) in enumerate(zip(expected, actual)):
|
|
140
|
+
yield from differences(left, right, f'{path}[{index}]')
|
|
141
|
+
elif expected != actual:
|
|
142
|
+
yield path
|
|
143
|
+
import itertools
|
|
144
|
+
print('different fields:', ', '.join(itertools.islice(differences(
|
|
145
|
+
json.loads(destination(name).read_text()), json.loads(text)), 12)))
|
|
146
|
+
raise SystemExit('offline replay differs: '+name)
|
|
147
|
+
readme = (HERE/'README.md').read_text()
|
|
148
|
+
if '<!-- BEGIN REPLAY TABLES -->\n'+result['tables.md']+'<!-- END REPLAY TABLES -->' not in readme:
|
|
149
|
+
raise SystemExit('offline replay differs: README tables')
|
|
150
|
+
print('offline replay PASS: 40 episodes; 621 hashes; ledger, groups, pairs, tables and provenance match')
|
|
151
|
+
else:
|
|
152
|
+
for name, text in result.items():
|
|
153
|
+
path = destination(name)
|
|
154
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
155
|
+
path.write_text(text)
|
|
156
|
+
readme = HERE/'README.md'
|
|
157
|
+
content = readme.read_text()
|
|
158
|
+
if '<!-- BEGIN REPLAY TABLES -->' in content:
|
|
159
|
+
import re
|
|
160
|
+
content = re.sub(r'<!-- BEGIN REPLAY TABLES -->.*?<!-- END REPLAY TABLES -->',
|
|
161
|
+
lambda _: '<!-- BEGIN REPLAY TABLES -->\n'+result['tables.md']+'<!-- END REPLAY TABLES -->', content, flags=re.S)
|
|
162
|
+
readme.write_text(content)
|
|
163
|
+
print('regenerated offline evidence:', len(result), 'files')
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if __name__ == '__main__':
|
|
167
|
+
main()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Metric-specific denominators and deterministic descriptive pairs."""
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def quality_included(row):
|
|
6
|
+
return not row.get('preflight') and (row.get('classification') != 'inconclusive' or row.get('budget_failure'))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def summarize_groups(rows):
|
|
10
|
+
groups = defaultdict(list)
|
|
11
|
+
for row in rows:
|
|
12
|
+
groups[(row['series'], row['model']['engine'], row['workload'], row['arm'])].append(row)
|
|
13
|
+
result = []
|
|
14
|
+
for key, group in sorted(groups.items()):
|
|
15
|
+
included = [row for row in group if quality_included(row)]
|
|
16
|
+
record = dict(zip(('series', 'engine', 'workload', 'arm'), key))
|
|
17
|
+
record.update(n_attempted=len(group), n_quality_included=len(included),
|
|
18
|
+
n_quality_excluded=len(group)-len(included),
|
|
19
|
+
artifact_passes=sum(bool(r['independent_grader'].get('pass')) and not r.get('budget_failure') for r in included),
|
|
20
|
+
budget_failures=sum(bool(r.get('budget_failure')) for r in included))
|
|
21
|
+
for output, field in [('reference_bytes', 'reference_returned_bytes'),
|
|
22
|
+
('exact_reference_bytes_lower_bound', 'exact_reference_bytes_lower_bound'),
|
|
23
|
+
('mean_wall_seconds', 'wall_seconds'),
|
|
24
|
+
('api_equivalent_cost_usd', 'api_equivalent_cost_usd'),
|
|
25
|
+
('api_equivalent_input_cost_usd', 'api_equivalent_input_cost_usd')]:
|
|
26
|
+
known = [r[field] for r in included if r.get(field) is not None]
|
|
27
|
+
record['n_'+output+'_included'] = len(known)
|
|
28
|
+
record['n_'+output+'_excluded'] = len(group)-len(known)
|
|
29
|
+
# Missing data never becomes zero. A known subtotal is explicitly
|
|
30
|
+
# different from an unknown group total.
|
|
31
|
+
record[output+'_known_subtotal'] = sum(known) if known else None
|
|
32
|
+
record[output] = (sum(known)/len(known) if output.startswith('mean_') else sum(known)) if known and len(known) == len(included) else None
|
|
33
|
+
result.append(record)
|
|
34
|
+
return result
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def paired_rows(rows):
|
|
38
|
+
cells = defaultdict(dict)
|
|
39
|
+
for row in rows:
|
|
40
|
+
if quality_included(row):
|
|
41
|
+
key = (row['series'], row['model']['engine'], row['workload'], row['repeat'])
|
|
42
|
+
if row['arm'] in cells[key]:
|
|
43
|
+
raise ValueError('duplicate arm in paired cell')
|
|
44
|
+
cells[key][row['arm']] = row
|
|
45
|
+
pairs = []
|
|
46
|
+
for key, arms in sorted(cells.items()):
|
|
47
|
+
pair = dict(zip(('series', 'engine', 'workload', 'repeat'), key))
|
|
48
|
+
for field in ('reference_returned_bytes', 'api_equivalent_input_cost_usd', 'api_equivalent_cost_usd', 'wall_seconds'):
|
|
49
|
+
a, b = (arms.get(arm, {}).get(field) for arm in ('A', 'B'))
|
|
50
|
+
known = a is not None and b is not None
|
|
51
|
+
pair[field] = {'included': known, 'A': a, 'B': b,
|
|
52
|
+
'delta_percent': (b-a)/a*100 if known and a else None}
|
|
53
|
+
pairs.append(pair)
|
|
54
|
+
return pairs
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def report_tables(rows, pairs):
|
|
58
|
+
lines = ['<!-- Generated by replay.py; parent-stream content attribution only. -->',
|
|
59
|
+
'| Family | Model | Pass / quality n | Excluded attempts |',
|
|
60
|
+
'|---|---|---:|---:|']
|
|
61
|
+
families = defaultdict(list)
|
|
62
|
+
for row in rows:
|
|
63
|
+
if not row.get('preflight'):
|
|
64
|
+
name = 'True Fable' if 'fable' in row['series'] else row['workload']
|
|
65
|
+
families[(name, row['model']['engine'])].append(row)
|
|
66
|
+
for (name, engine), group in sorted(families.items()):
|
|
67
|
+
included = [r for r in group if quality_included(r)]
|
|
68
|
+
passes = sum(bool(r['independent_grader'].get('pass')) and not r.get('budget_failure') for r in included)
|
|
69
|
+
lines.append(f'| {name} | {engine} | {passes}/{len(included)} | {len(group)-len(included)} |')
|
|
70
|
+
for field, title, precision in [('reference_returned_bytes', 'Attributable reference bytes (lower bound)', 0),
|
|
71
|
+
('api_equivalent_input_cost_usd', 'List-price input cost (frozen telemetry)', 6)]:
|
|
72
|
+
lines.extend(['', '### '+title, '', '| Family | Model | Included / candidate pairs | A | B | Delta |', '|---|---|---:|---:|---:|---:|'])
|
|
73
|
+
grouped = defaultdict(list)
|
|
74
|
+
for pair in pairs:
|
|
75
|
+
name = 'True Fable' if 'fable' in pair['series'] else pair['workload']
|
|
76
|
+
grouped[(name, pair['engine'])].append(pair[field])
|
|
77
|
+
for (name, engine), group in sorted(grouped.items()):
|
|
78
|
+
known = [p for p in group if p['included']]
|
|
79
|
+
a, b = (sum(p[arm] for p in known) for arm in ('A', 'B'))
|
|
80
|
+
values = [f'{a:.{precision}f}', f'{b:.{precision}f}', f'{(b-a)/a*100:+.1f}%' if a else 'unknown'] if known else ['unknown']*3
|
|
81
|
+
lines.append(f'| {name} | {engine} | {len(known)}/{len(group)} | '+ ' | '.join(values)+' |')
|
|
82
|
+
return '\n'.join(lines)+'\n'
|