touchstone-us 0.1.0__tar.gz
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.
- touchstone_us-0.1.0/.gitignore +8 -0
- touchstone_us-0.1.0/LICENSE +40 -0
- touchstone_us-0.1.0/PKG-INFO +9 -0
- touchstone_us-0.1.0/PROTOCOL.md +92 -0
- touchstone_us-0.1.0/app.js +151 -0
- touchstone_us-0.1.0/base.css +128 -0
- touchstone_us-0.1.0/examples/cpu-correct.json +44 -0
- touchstone_us-0.1.0/examples/cpu-crash.json +44 -0
- touchstone_us-0.1.0/examples/cpu-drift.json +44 -0
- touchstone_us-0.1.0/examples/cpu-missing.json +44 -0
- touchstone_us-0.1.0/examples/cpu-slow.json +44 -0
- touchstone_us-0.1.0/examples/cpu-timeout.json +44 -0
- touchstone_us-0.1.0/examples/cpu-upgrade.json +44 -0
- touchstone_us-0.1.0/examples/cuda-correct.json +44 -0
- touchstone_us-0.1.0/examples/cuda-drift.json +44 -0
- touchstone_us-0.1.0/examples/cuda-slow.json +44 -0
- touchstone_us-0.1.0/examples/cuda-upgrade.json +44 -0
- touchstone_us-0.1.0/examples/fixtures.json +651 -0
- touchstone_us-0.1.0/examples/workload.py +110 -0
- touchstone_us-0.1.0/fixtures.js +48 -0
- touchstone_us-0.1.0/index.html +76 -0
- touchstone_us-0.1.0/pyproject.toml +65 -0
- touchstone_us-0.1.0/responsive.css +21 -0
- touchstone_us-0.1.0/rl_examples/bad-reference.json +190 -0
- touchstone_us-0.1.0/rl_examples/broken-control.json +190 -0
- touchstone_us-0.1.0/rl_examples/cache-leak.json +190 -0
- touchstone_us-0.1.0/rl_examples/fixed-grader.json +190 -0
- touchstone_us-0.1.0/rl_examples/malformed-grader.json +190 -0
- touchstone_us-0.1.0/rl_examples/weak-grader.json +190 -0
- touchstone_us-0.1.0/styles.css +44 -0
- touchstone_us-0.1.0/touchstone/__init__.py +1 -0
- touchstone_us-0.1.0/touchstone/agent.py +423 -0
- touchstone_us-0.1.0/touchstone/app.py +272 -0
- touchstone_us-0.1.0/touchstone/artifacts.py +31 -0
- touchstone_us-0.1.0/touchstone/attest.py +178 -0
- touchstone_us-0.1.0/touchstone/catalog.py +67 -0
- touchstone_us-0.1.0/touchstone/cli.py +184 -0
- touchstone_us-0.1.0/touchstone/compare.py +271 -0
- touchstone_us-0.1.0/touchstone/doctor.py +218 -0
- touchstone_us-0.1.0/touchstone/models.py +158 -0
- touchstone_us-0.1.0/touchstone/packages.py +43 -0
- touchstone_us-0.1.0/touchstone/redact.py +68 -0
- touchstone_us-0.1.0/touchstone/rl/__init__.py +1 -0
- touchstone_us-0.1.0/touchstone/rl/analyze.py +330 -0
- touchstone_us-0.1.0/touchstone/rl/answer.py +391 -0
- touchstone_us-0.1.0/touchstone/rl/api.py +118 -0
- touchstone_us-0.1.0/touchstone/rl/attacks.py +116 -0
- touchstone_us-0.1.0/touchstone/rl/catalog.py +72 -0
- touchstone_us-0.1.0/touchstone/rl/cli.py +209 -0
- touchstone_us-0.1.0/touchstone/rl/diff.py +147 -0
- touchstone_us-0.1.0/touchstone/rl/engine.py +380 -0
- touchstone_us-0.1.0/touchstone/rl/harnesses/answer.py +97 -0
- touchstone_us-0.1.0/touchstone/rl/harnesses/grade.py +102 -0
- touchstone_us-0.1.0/touchstone/rl/harnesses/invoke.py +16 -0
- touchstone_us-0.1.0/touchstone/rl/models.py +321 -0
- touchstone_us-0.1.0/touchstone/rl/onboard.py +234 -0
- touchstone_us-0.1.0/touchstone/rl/service.py +266 -0
- touchstone_us-0.1.0/touchstone/runner.py +351 -0
- touchstone_us-0.1.0/touchstone/safety/__init__.py +1 -0
- touchstone_us-0.1.0/touchstone/safety/adapters.py +108 -0
- touchstone_us-0.1.0/touchstone/safety/api.py +71 -0
- touchstone_us-0.1.0/touchstone/safety/cli.py +166 -0
- touchstone_us-0.1.0/touchstone/safety/codex.py +73 -0
- touchstone_us-0.1.0/touchstone/safety/compare.py +35 -0
- touchstone_us-0.1.0/touchstone/safety/demo.py +58 -0
- touchstone_us-0.1.0/touchstone/safety/engine.py +146 -0
- touchstone_us-0.1.0/touchstone/safety/execution.py +18 -0
- touchstone_us-0.1.0/touchstone/safety/generator.py +42 -0
- touchstone_us-0.1.0/touchstone/safety/generator_worker.py +7 -0
- touchstone_us-0.1.0/touchstone/safety/models.py +137 -0
- touchstone_us-0.1.0/touchstone/safety/store.py +244 -0
- touchstone_us-0.1.0/touchstone/safety/sync.py +64 -0
- touchstone_us-0.1.0/touchstone/safety/worker.py +31 -0
- touchstone_us-0.1.0/touchstone/service.py +329 -0
- touchstone_us-0.1.0/touchstone/store.py +206 -0
- touchstone_us-0.1.0/web/demo.js +13 -0
- touchstone_us-0.1.0/web/docs.css +43 -0
- touchstone_us-0.1.0/web/docs.html +226 -0
- touchstone_us-0.1.0/web/index.html +469 -0
- touchstone_us-0.1.0/web/rl.css +172 -0
- touchstone_us-0.1.0/web/rl.html +377 -0
- touchstone_us-0.1.0/web/rl.js +741 -0
- touchstone_us-0.1.0/web/safety-public.html +38 -0
- touchstone_us-0.1.0/web/safety.css +119 -0
- touchstone_us-0.1.0/web/safety.html +70 -0
- touchstone_us-0.1.0/web/safety.js +481 -0
- touchstone_us-0.1.0/web/workspace.css +888 -0
- touchstone_us-0.1.0/web/workspace.js +688 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
TouchStone Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Merrick Zheng. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and its accompanying files (the "Software") are proprietary and
|
|
6
|
+
confidential. The Software is licensed, not sold.
|
|
7
|
+
|
|
8
|
+
1. Permitted use. Subject to a separate written agreement with the copyright
|
|
9
|
+
holder (such as a pilot, evaluation or subscription agreement), you may
|
|
10
|
+
install and run the Software on infrastructure you control for your own
|
|
11
|
+
internal purposes. If no such agreement exists, you may install and run the
|
|
12
|
+
Software solely to evaluate it for up to thirty (30) days.
|
|
13
|
+
|
|
14
|
+
2. Restrictions. Except as expressly permitted above or by applicable law that
|
|
15
|
+
cannot be excluded by contract, you may not: (a) copy, distribute, sublicense,
|
|
16
|
+
sell, rent, lease or otherwise make the Software available to any third
|
|
17
|
+
party; (b) modify, translate or create derivative works of the Software;
|
|
18
|
+
(c) remove or alter any copyright, license or attribution notice; or
|
|
19
|
+
(d) use the Software to build a competing product or service.
|
|
20
|
+
|
|
21
|
+
3. Ownership. The copyright holder retains all right, title and interest in
|
|
22
|
+
the Software. No rights are granted by implication, estoppel or otherwise
|
|
23
|
+
except those expressly stated in this license.
|
|
24
|
+
|
|
25
|
+
4. Termination. This license terminates automatically if you breach any of its
|
|
26
|
+
terms. On termination you must stop using the Software and delete all
|
|
27
|
+
copies in your possession.
|
|
28
|
+
|
|
29
|
+
5. Disclaimer of warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
|
|
30
|
+
OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
31
|
+
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
32
|
+
NON-INFRINGEMENT.
|
|
33
|
+
|
|
34
|
+
6. Limitation of liability. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE
|
|
35
|
+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
36
|
+
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
37
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
38
|
+
|
|
39
|
+
Third-party components bundled with or depended on by the Software remain
|
|
40
|
+
under their own licenses.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Workload contract
|
|
2
|
+
|
|
3
|
+
The runner executes trusted OCI images with a manifest command (an argv array;
|
|
4
|
+
there is no implicit host shell). The frozen workload file and fixture are
|
|
5
|
+
mounted read-only at `/workload`. Images are resolved to local immutable IDs
|
|
6
|
+
before the first measurement. Registry digests are recorded when available.
|
|
7
|
+
|
|
8
|
+
## Start from the included example
|
|
9
|
+
|
|
10
|
+
1. Keep `manifest.json`, `workload.py` and `fixtures.json` together.
|
|
11
|
+
2. Replace the baseline and candidate images/commands with your own trusted
|
|
12
|
+
test implementations. The command must emit the JSON contract below.
|
|
13
|
+
3. Supply case IDs and expected numeric vectors in the fixture. The `inputs`
|
|
14
|
+
object carries your workload's data; the controller does not interpret it.
|
|
15
|
+
4. Import the three files in the local workspace, review the policy and run.
|
|
16
|
+
|
|
17
|
+
File basenames in the manifest must match the workload/fixture filenames.
|
|
18
|
+
Input files are limited to 1 MB each. One comparison executes three to ten
|
|
19
|
+
paired trials, alternating baseline-first and candidate-first order. Workloads
|
|
20
|
+
need no network and should not download models during measurement. Put their
|
|
21
|
+
dependencies and model data in your approved image or the bounded fixture.
|
|
22
|
+
|
|
23
|
+
## Manifest
|
|
24
|
+
|
|
25
|
+
Use the starter's manifest. `baseline` and `candidate` each contain `image`
|
|
26
|
+
and `command`. `device` is `cpu` or `cuda`. `repeats` is 3-10,
|
|
27
|
+
`timeout_seconds` is 5-180, `memory_mb` is 256-8192, and `cpus` is 1-4.
|
|
28
|
+
The policy covers throughput retention, amortized time ratio, absolute output
|
|
29
|
+
error, reported memory, failed samples, minimum samples and timing CV.
|
|
30
|
+
The manifest schema rejects unknown fields and invalid/non-finite values.
|
|
31
|
+
|
|
32
|
+
## Fixture
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"schema_version": 1,
|
|
37
|
+
"cases": [{"id": "case-01", "values": [0.25, 0.75]}],
|
|
38
|
+
"inputs": {"your_workload_data": "goes here"}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Case IDs must be unique. There are at most 256 cases and 256 numeric values per
|
|
43
|
+
case, with at most 4096 values in total. Values are finite. The controller requires exact ID and vector-length
|
|
44
|
+
coverage from each execution and calculates absolute errors against this file.
|
|
45
|
+
|
|
46
|
+
## Standard output
|
|
47
|
+
|
|
48
|
+
Emit exactly one JSON object; send diagnostic text to stderr. The example
|
|
49
|
+
below is a schema illustration, not a measurement to reuse.
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"schema_version": 1,
|
|
54
|
+
"device": "cpu",
|
|
55
|
+
"samples": 1000,
|
|
56
|
+
"duration_seconds": 1.5,
|
|
57
|
+
"peak_memory_mb": 28.0,
|
|
58
|
+
"memory_kind": "process_rss",
|
|
59
|
+
"failures": 0,
|
|
60
|
+
"outputs": [{"id": "case-01", "values": [0.25, 0.75]}],
|
|
61
|
+
"runtime": {"python": "3.12", "workload": "your-suite-v1"}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Use `cuda_allocated` for CUDA memory and `process_rss` for CPU memory. CUDA
|
|
66
|
+
workloads must fail if CUDA is unavailable; silent CPU fallback cannot qualify
|
|
67
|
+
the requested contract. Synchronize CUDA before and after the measured region.
|
|
68
|
+
Keep initialization/warmup outside that region. `samples / duration_seconds`
|
|
69
|
+
gives throughput; its reciprocal gives amortized processing time per sample.
|
|
70
|
+
For a batched workload this is not request latency, nor p95 or p99. The v1
|
|
71
|
+
JSON fields `latency_ms` and `max_latency_ratio` retain their original names;
|
|
72
|
+
they represent this derived amortized time and its candidate/baseline ratio.
|
|
73
|
+
These are trusted test-instrumentation measurements, not tamper-proof telemetry.
|
|
74
|
+
|
|
75
|
+
## Results and boundaries
|
|
76
|
+
|
|
77
|
+
- `eligible`: declared checks pass; a human release owner must still decide.
|
|
78
|
+
- `hold`: at least one policy check fails; inspect the evidence and fix the candidate.
|
|
79
|
+
- `inconclusive`: execution, reference coverage, comparability or repeatability
|
|
80
|
+
is incomplete. A crash, missing output or timeout never becomes a pass.
|
|
81
|
+
- Cancelled/interrupted/error executions retain diagnostic evidence separately.
|
|
82
|
+
|
|
83
|
+
The included examples are small real classifier inference, with deliberately
|
|
84
|
+
injected faults in named variants. They are not a discovered upstream bug,
|
|
85
|
+
representative LLM benchmark, convergence test or customer validation.
|
|
86
|
+
|
|
87
|
+
This MVP uses rootless Podman, a non-root workload user, no container network,
|
|
88
|
+
no capabilities, resource/process limits and bounded logs. CPU root filesystems
|
|
89
|
+
are read-only. NVIDIA CDI needs a temporary writable image layer to initialize
|
|
90
|
+
its loader on this WSL host; GPU workloads still run non-root and inputs remain
|
|
91
|
+
read-only. CUDA GPU memory is not limited by the CPU cgroup memory setting.
|
|
92
|
+
Only run trusted operator code. Containers are not a hostile-code security boundary.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { checks, scenarios, evaluate, disposition } from './fixtures.js';
|
|
2
|
+
const get = id => document.getElementById(id);
|
|
3
|
+
const requestedScenario = new URL(location.href).searchParams.get('scenario');
|
|
4
|
+
let selected = Object.hasOwn(scenarios, requestedScenario) ? requestedScenario : 'throughput';
|
|
5
|
+
const checkList = get('check-list');
|
|
6
|
+
const decision = get('decision');
|
|
7
|
+
const status = get('review-status');
|
|
8
|
+
const format = new Intl.NumberFormat('en-US', { maximumFractionDigits: 1 });
|
|
9
|
+
function checkDetail(key, scenario) {
|
|
10
|
+
const { baseline, candidate } = scenario.fixture;
|
|
11
|
+
if (key === 'hardware') return `${baseline.samples} baseline / ${candidate.samples} candidate requests`;
|
|
12
|
+
if (key === 'throughput') return `${format.format(baseline.throughput)} → ${format.format(candidate.throughput)} tokens/s`;
|
|
13
|
+
if (key === 'fidelity') return `Observed max error: ${candidate.error}`;
|
|
14
|
+
return `${format.format(candidate.memoryGb)} GB peak / ${candidate.failures} failed requests`;
|
|
15
|
+
}
|
|
16
|
+
function renderChecks(results) {
|
|
17
|
+
checkList.replaceChildren(...checks.map(check => {
|
|
18
|
+
const row = document.createElement('div');
|
|
19
|
+
const outcome = !results ? 'pending' : results[check.key] === null ? 'inconclusive' : results[check.key] ? 'pass' : 'fail';
|
|
20
|
+
row.className = `check-row ${outcome}`;
|
|
21
|
+
const symbol = document.createElement('span');
|
|
22
|
+
symbol.className = 'check-symbol';
|
|
23
|
+
symbol.setAttribute('aria-hidden', 'true');
|
|
24
|
+
symbol.textContent = { pass: '✓', fail: '!', pending: '○', inconclusive: '—' }[outcome];
|
|
25
|
+
const label = document.createElement('span');
|
|
26
|
+
label.className = 'check-label';
|
|
27
|
+
const name = document.createElement('strong');
|
|
28
|
+
name.textContent = check.label;
|
|
29
|
+
label.append(name);
|
|
30
|
+
if (results && outcome !== 'inconclusive') {
|
|
31
|
+
const detail = document.createElement('small');
|
|
32
|
+
detail.textContent = checkDetail(check.key, scenarios[selected]);
|
|
33
|
+
label.append(detail);
|
|
34
|
+
}
|
|
35
|
+
const value = document.createElement('span');
|
|
36
|
+
value.textContent = { pass: 'Pass', fail: 'Fail', pending: 'Not run', inconclusive: 'Not qualified' }[outcome];
|
|
37
|
+
row.append(symbol, label, value);
|
|
38
|
+
return row;
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
function selectScenario(key) {
|
|
42
|
+
selected = key;
|
|
43
|
+
const url = new URL(location.href);
|
|
44
|
+
url.searchParams.set('scenario', key);
|
|
45
|
+
history.replaceState(null, '', url);
|
|
46
|
+
const scenario = scenarios[key];
|
|
47
|
+
for (const button of document.querySelectorAll('[data-scenario]')) {
|
|
48
|
+
const active = button.dataset.scenario === key;
|
|
49
|
+
button.classList.toggle('active', active);
|
|
50
|
+
button.setAttribute('aria-pressed', String(active));
|
|
51
|
+
}
|
|
52
|
+
get('release-id').textContent = `Candidate stack ${scenario.release}`;
|
|
53
|
+
get('scenario-title').textContent = scenario.title;
|
|
54
|
+
get('baseline-name').textContent = scenario.baselineName;
|
|
55
|
+
get('candidate-name').textContent = scenario.candidateName;
|
|
56
|
+
get('sample-context').textContent = selected === 'hardware' ? 'H100 baseline / A100 candidate • 100 sampled requests per stack' : 'Matched H100 80 GB host profile • 100 sampled requests per stack';
|
|
57
|
+
status.className = 'status idle';
|
|
58
|
+
status.textContent = 'Not checked';
|
|
59
|
+
decision.className = 'decision';
|
|
60
|
+
decision.querySelector('.decision-symbol').textContent = '○';
|
|
61
|
+
decision.querySelector('strong').textContent = 'Choose a candidate. Run its checks.';
|
|
62
|
+
decision.querySelector('p').textContent = 'The decision and supporting evidence will appear here.';
|
|
63
|
+
get('evidence-details').hidden = true;
|
|
64
|
+
get('evidence-details').open = false;
|
|
65
|
+
get('compare-fixed').hidden = true;
|
|
66
|
+
get('run-checks').textContent = 'Run sample checks ↗';
|
|
67
|
+
renderChecks();
|
|
68
|
+
}
|
|
69
|
+
get('run-checks').addEventListener('click', () => {
|
|
70
|
+
const scenario = scenarios[selected];
|
|
71
|
+
const results = evaluate(scenario.fixture);
|
|
72
|
+
const result = disposition(results);
|
|
73
|
+
renderChecks(results);
|
|
74
|
+
status.className = `status ${result}`;
|
|
75
|
+
status.textContent = { ready: 'Eligible for review', blocked: 'Hold', inconclusive: 'Rerun required' }[result];
|
|
76
|
+
decision.className = `decision ${result}`;
|
|
77
|
+
decision.querySelector('.decision-symbol').textContent = { ready: '✓', blocked: '!', inconclusive: '↺' }[result];
|
|
78
|
+
decision.querySelector('strong').textContent = {
|
|
79
|
+
ready: 'Policy checks pass. Owner approval is next.',
|
|
80
|
+
blocked: selected === 'fidelity' ? 'Hold. The faster candidate fails output fidelity.' : 'Hold. Throughput falls below the release threshold.',
|
|
81
|
+
inconclusive: 'Rerun required. The hardware profiles do not match.',
|
|
82
|
+
}[result];
|
|
83
|
+
decision.querySelector('p').textContent = scenario.explanation;
|
|
84
|
+
get('evidence-details').hidden = false;
|
|
85
|
+
get('evidence-output').textContent = JSON.stringify(scenario.evidence, null, 2);
|
|
86
|
+
get('evidence-explanation').textContent = 'Illustrative evidence only. These image identities, bundles and results are synthetic; no live infrastructure is connected.';
|
|
87
|
+
get('compare-fixed').hidden = selected !== 'throughput' && selected !== 'fidelity';
|
|
88
|
+
get('run-checks').textContent = 'Run sample checks again ↗';
|
|
89
|
+
});
|
|
90
|
+
for (const button of document.querySelectorAll('[data-scenario]')) button.addEventListener('click', () => selectScenario(button.dataset.scenario));
|
|
91
|
+
get('compare-fixed').addEventListener('click', () => {
|
|
92
|
+
selectScenario('ready');
|
|
93
|
+
get('run-checks').click();
|
|
94
|
+
get('run-checks').focus({ preventScroll: true });
|
|
95
|
+
});
|
|
96
|
+
const dialog = get('pilot-dialog');
|
|
97
|
+
get('pilot-brief').addEventListener('click', () => dialog.showModal());
|
|
98
|
+
get('close-pilot').addEventListener('click', () => dialog.close());
|
|
99
|
+
get('pilot-done').addEventListener('click', () => {
|
|
100
|
+
dialog.close();
|
|
101
|
+
get('sample').scrollIntoView({ behavior: scrollBehavior() });
|
|
102
|
+
get('run-checks').focus({ preventScroll: true });
|
|
103
|
+
});
|
|
104
|
+
dialog.addEventListener('click', event => {
|
|
105
|
+
if (event.target === dialog) {
|
|
106
|
+
const bounds = dialog.getBoundingClientRect();
|
|
107
|
+
if (event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom) dialog.close();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
const scrollBehavior = () => matchMedia('(prefers-reduced-motion: reduce)').matches ? 'instant' : 'smooth';
|
|
111
|
+
for (const link of document.querySelectorAll('[data-jump]')) link.addEventListener('click', event => {
|
|
112
|
+
event.preventDefault();
|
|
113
|
+
selectScenario(link.dataset.jump);
|
|
114
|
+
get('sample').scrollIntoView({ behavior: scrollBehavior() });
|
|
115
|
+
get('run-checks').focus({ preventScroll: true });
|
|
116
|
+
});
|
|
117
|
+
const tabs = [...document.querySelectorAll('[role=tab]')];
|
|
118
|
+
function selectTab(tab) {
|
|
119
|
+
for (const other of tabs) {
|
|
120
|
+
const active = other === tab;
|
|
121
|
+
other.setAttribute('aria-selected', String(active));
|
|
122
|
+
other.tabIndex = active ? 0 : -1;
|
|
123
|
+
get(other.getAttribute('aria-controls')).hidden = !active;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
for (const tab of tabs) {
|
|
127
|
+
tab.addEventListener('click', () => selectTab(tab));
|
|
128
|
+
tab.addEventListener('keydown', event => {
|
|
129
|
+
const step = { ArrowRight: 1, ArrowLeft: -1 }[event.key];
|
|
130
|
+
if (!step) return;
|
|
131
|
+
const next = tabs[(tabs.indexOf(tab) + step + tabs.length) % tabs.length];
|
|
132
|
+
selectTab(next);
|
|
133
|
+
next.focus();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
get('copy-code').addEventListener('click', async () => {
|
|
137
|
+
const panel = document.querySelector('[role=tabpanel]:not([hidden])');
|
|
138
|
+
const note = get('copy-status');
|
|
139
|
+
try {
|
|
140
|
+
await navigator.clipboard.writeText(panel.textContent);
|
|
141
|
+
note.textContent = 'Copied to the clipboard.';
|
|
142
|
+
} catch {
|
|
143
|
+
getSelection().selectAllChildren(panel);
|
|
144
|
+
note.textContent = 'Copy is unavailable here; the command is selected.';
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
const header = document.querySelector('.site-header');
|
|
148
|
+
const markScrolled = () => header.classList.toggle('scrolled', scrollY > 8);
|
|
149
|
+
addEventListener('scroll', markScrolled, { passive: true });
|
|
150
|
+
markScrolled();
|
|
151
|
+
selectScenario(selected);
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
@font-face {
|
|
2
|
+
font-family:TouchStone Sans;
|
|
3
|
+
src:local("Bahnschrift"),local("Arial");
|
|
4
|
+
font-display:swap;
|
|
5
|
+
}
|
|
6
|
+
:root {
|
|
7
|
+
--ink:#142338;
|
|
8
|
+
--muted:#58687c;
|
|
9
|
+
--cobalt:#254f9b;
|
|
10
|
+
--cobalt-deep:#213caf;
|
|
11
|
+
--ice:#f1f5fa;
|
|
12
|
+
--line:#dce3ec;
|
|
13
|
+
--pale:#e9edff;
|
|
14
|
+
--green:#227b59;
|
|
15
|
+
--amber:#9c6411;
|
|
16
|
+
--white:#fff;
|
|
17
|
+
--radius:12px;
|
|
18
|
+
}
|
|
19
|
+
* {
|
|
20
|
+
box-sizing:border-box;
|
|
21
|
+
}
|
|
22
|
+
html {
|
|
23
|
+
scroll-behavior:smooth;
|
|
24
|
+
scroll-padding-top:96px;
|
|
25
|
+
}
|
|
26
|
+
body {
|
|
27
|
+
margin:0;
|
|
28
|
+
background:var(--white);
|
|
29
|
+
color:var(--ink);
|
|
30
|
+
font-family:"TouchStone Sans","Segoe UI",Arial,sans-serif;
|
|
31
|
+
font-size:16px;
|
|
32
|
+
line-height:1.65;
|
|
33
|
+
-webkit-font-smoothing:antialiased;
|
|
34
|
+
}
|
|
35
|
+
button,a {
|
|
36
|
+
-webkit-tap-highlight-color:transparent;
|
|
37
|
+
}
|
|
38
|
+
button {
|
|
39
|
+
font:inherit;
|
|
40
|
+
cursor:pointer;
|
|
41
|
+
}
|
|
42
|
+
a {
|
|
43
|
+
color:inherit;
|
|
44
|
+
text-decoration:none;
|
|
45
|
+
}
|
|
46
|
+
a,button,summary {
|
|
47
|
+
touch-action:manipulation;
|
|
48
|
+
}
|
|
49
|
+
a:focus-visible,button:focus-visible,summary:focus-visible {
|
|
50
|
+
outline:3px solid #b25816;
|
|
51
|
+
outline-offset:5px;
|
|
52
|
+
}
|
|
53
|
+
h1,h2,h3,p {
|
|
54
|
+
margin:0;
|
|
55
|
+
}
|
|
56
|
+
h1,h2,h3 {
|
|
57
|
+
text-wrap:balance;
|
|
58
|
+
}
|
|
59
|
+
p {
|
|
60
|
+
max-width:68ch;
|
|
61
|
+
}
|
|
62
|
+
h1 {
|
|
63
|
+
font-size:clamp(48px,5.2vw,78px);
|
|
64
|
+
line-height:1.06;
|
|
65
|
+
letter-spacing:-.055em;
|
|
66
|
+
font-weight:650;
|
|
67
|
+
}
|
|
68
|
+
h2 {
|
|
69
|
+
font-size:clamp(34px,3.1vw,48px);
|
|
70
|
+
line-height:1.15;
|
|
71
|
+
letter-spacing:-.04em;
|
|
72
|
+
font-weight:650;
|
|
73
|
+
}
|
|
74
|
+
h3 {
|
|
75
|
+
font-size:19px;
|
|
76
|
+
line-height:1.35;
|
|
77
|
+
font-weight:650;
|
|
78
|
+
letter-spacing:-.015em;
|
|
79
|
+
}
|
|
80
|
+
.wrap {
|
|
81
|
+
width:min(1200px,calc(100% - 96px));
|
|
82
|
+
margin-inline:auto;
|
|
83
|
+
}
|
|
84
|
+
.site-header {
|
|
85
|
+
display:flex;
|
|
86
|
+
align-items:center;
|
|
87
|
+
justify-content:space-between;
|
|
88
|
+
min-height:104px;
|
|
89
|
+
}
|
|
90
|
+
.brand {
|
|
91
|
+
display:inline-flex;
|
|
92
|
+
align-items:center;
|
|
93
|
+
gap:10px;
|
|
94
|
+
font-size:24px;
|
|
95
|
+
font-weight:680;
|
|
96
|
+
letter-spacing:-.055em;
|
|
97
|
+
line-height:1;
|
|
98
|
+
}
|
|
99
|
+
.brand svg {
|
|
100
|
+
height:34px;
|
|
101
|
+
width:34px;
|
|
102
|
+
stroke:var(--cobalt);
|
|
103
|
+
fill:none;
|
|
104
|
+
stroke-width:3.4;
|
|
105
|
+
stroke-linejoin:round;
|
|
106
|
+
stroke-linecap:round;
|
|
107
|
+
}
|
|
108
|
+
.site-header nav {
|
|
109
|
+
display:flex;
|
|
110
|
+
align-items:center;
|
|
111
|
+
gap:31px;
|
|
112
|
+
font-size:14px;
|
|
113
|
+
font-weight:550;
|
|
114
|
+
}
|
|
115
|
+
.site-header nav a {
|
|
116
|
+
padding:8px 0;
|
|
117
|
+
}
|
|
118
|
+
.site-header nav a:hover,.text-link:hover,.site-footer>a:last-child:hover {
|
|
119
|
+
color:var(--cobalt);
|
|
120
|
+
}
|
|
121
|
+
.site-header nav .nav-cta {
|
|
122
|
+
padding:10px 17px;
|
|
123
|
+
border:1px solid var(--line);
|
|
124
|
+
border-radius:6px;
|
|
125
|
+
}
|
|
126
|
+
.nav-cta:hover {
|
|
127
|
+
background:var(--ice);
|
|
128
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"name": "CPU / Reference match",
|
|
4
|
+
"description": "Measured inference with identical correct implementations. Performance can still be noisy.",
|
|
5
|
+
"demonstration": true,
|
|
6
|
+
"device": "cpu",
|
|
7
|
+
"baseline": {
|
|
8
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
9
|
+
"command": [
|
|
10
|
+
"python",
|
|
11
|
+
"/workload/workload.py",
|
|
12
|
+
"--device",
|
|
13
|
+
"cpu",
|
|
14
|
+
"--variant",
|
|
15
|
+
"correct"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"candidate": {
|
|
19
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
20
|
+
"command": [
|
|
21
|
+
"python",
|
|
22
|
+
"/workload/workload.py",
|
|
23
|
+
"--device",
|
|
24
|
+
"cpu",
|
|
25
|
+
"--variant",
|
|
26
|
+
"correct"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"workload_file": "workload.py",
|
|
30
|
+
"fixture_file": "fixtures.json",
|
|
31
|
+
"repeats": 3,
|
|
32
|
+
"timeout_seconds": 60,
|
|
33
|
+
"memory_mb": 512,
|
|
34
|
+
"cpus": 2,
|
|
35
|
+
"policy": {
|
|
36
|
+
"min_throughput_ratio": 0.8,
|
|
37
|
+
"max_latency_ratio": 1.3,
|
|
38
|
+
"max_abs_error": 1e-05,
|
|
39
|
+
"max_peak_memory_mb": 1024.0,
|
|
40
|
+
"max_failures": 0,
|
|
41
|
+
"min_samples": 100,
|
|
42
|
+
"max_timing_cv": 0.3
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"name": "CPU / Injected execution failure",
|
|
4
|
+
"description": "Deliberately exits with status 3. The result must remain inconclusive.",
|
|
5
|
+
"demonstration": true,
|
|
6
|
+
"device": "cpu",
|
|
7
|
+
"baseline": {
|
|
8
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
9
|
+
"command": [
|
|
10
|
+
"python",
|
|
11
|
+
"/workload/workload.py",
|
|
12
|
+
"--device",
|
|
13
|
+
"cpu",
|
|
14
|
+
"--variant",
|
|
15
|
+
"correct"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"candidate": {
|
|
19
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
20
|
+
"command": [
|
|
21
|
+
"python",
|
|
22
|
+
"/workload/workload.py",
|
|
23
|
+
"--device",
|
|
24
|
+
"cpu",
|
|
25
|
+
"--variant",
|
|
26
|
+
"crash"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"workload_file": "workload.py",
|
|
30
|
+
"fixture_file": "fixtures.json",
|
|
31
|
+
"repeats": 3,
|
|
32
|
+
"timeout_seconds": 60,
|
|
33
|
+
"memory_mb": 512,
|
|
34
|
+
"cpus": 2,
|
|
35
|
+
"policy": {
|
|
36
|
+
"min_throughput_ratio": 0.8,
|
|
37
|
+
"max_latency_ratio": 1.3,
|
|
38
|
+
"max_abs_error": 1e-05,
|
|
39
|
+
"max_peak_memory_mb": 1024.0,
|
|
40
|
+
"max_failures": 0,
|
|
41
|
+
"min_samples": 100,
|
|
42
|
+
"max_timing_cv": 0.3
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"name": "CPU / Injected output regression",
|
|
4
|
+
"description": "Deliberately changes one probability by 0.05. A fault demonstration, not a discovered framework defect.",
|
|
5
|
+
"demonstration": true,
|
|
6
|
+
"device": "cpu",
|
|
7
|
+
"baseline": {
|
|
8
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
9
|
+
"command": [
|
|
10
|
+
"python",
|
|
11
|
+
"/workload/workload.py",
|
|
12
|
+
"--device",
|
|
13
|
+
"cpu",
|
|
14
|
+
"--variant",
|
|
15
|
+
"correct"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"candidate": {
|
|
19
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
20
|
+
"command": [
|
|
21
|
+
"python",
|
|
22
|
+
"/workload/workload.py",
|
|
23
|
+
"--device",
|
|
24
|
+
"cpu",
|
|
25
|
+
"--variant",
|
|
26
|
+
"drift"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"workload_file": "workload.py",
|
|
30
|
+
"fixture_file": "fixtures.json",
|
|
31
|
+
"repeats": 3,
|
|
32
|
+
"timeout_seconds": 60,
|
|
33
|
+
"memory_mb": 512,
|
|
34
|
+
"cpus": 2,
|
|
35
|
+
"policy": {
|
|
36
|
+
"min_throughput_ratio": 0.8,
|
|
37
|
+
"max_latency_ratio": 1.3,
|
|
38
|
+
"max_abs_error": 1e-05,
|
|
39
|
+
"max_peak_memory_mb": 1024.0,
|
|
40
|
+
"max_failures": 0,
|
|
41
|
+
"min_samples": 100,
|
|
42
|
+
"max_timing_cv": 0.3
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"name": "CPU / Incomplete output coverage",
|
|
4
|
+
"description": "Deliberately omits a fixture case. Incomplete evidence cannot qualify a release.",
|
|
5
|
+
"demonstration": true,
|
|
6
|
+
"device": "cpu",
|
|
7
|
+
"baseline": {
|
|
8
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
9
|
+
"command": [
|
|
10
|
+
"python",
|
|
11
|
+
"/workload/workload.py",
|
|
12
|
+
"--device",
|
|
13
|
+
"cpu",
|
|
14
|
+
"--variant",
|
|
15
|
+
"correct"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"candidate": {
|
|
19
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
20
|
+
"command": [
|
|
21
|
+
"python",
|
|
22
|
+
"/workload/workload.py",
|
|
23
|
+
"--device",
|
|
24
|
+
"cpu",
|
|
25
|
+
"--variant",
|
|
26
|
+
"missing"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"workload_file": "workload.py",
|
|
30
|
+
"fixture_file": "fixtures.json",
|
|
31
|
+
"repeats": 3,
|
|
32
|
+
"timeout_seconds": 60,
|
|
33
|
+
"memory_mb": 512,
|
|
34
|
+
"cpus": 2,
|
|
35
|
+
"policy": {
|
|
36
|
+
"min_throughput_ratio": 0.8,
|
|
37
|
+
"max_latency_ratio": 1.3,
|
|
38
|
+
"max_abs_error": 1e-05,
|
|
39
|
+
"max_peak_memory_mb": 1024.0,
|
|
40
|
+
"max_failures": 0,
|
|
41
|
+
"min_samples": 100,
|
|
42
|
+
"max_timing_cv": 0.3
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"name": "CPU / Injected performance regression",
|
|
4
|
+
"description": "Deliberately sleeps during inference. Actual timing is measured; the slowdown is intentional.",
|
|
5
|
+
"demonstration": true,
|
|
6
|
+
"device": "cpu",
|
|
7
|
+
"baseline": {
|
|
8
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
9
|
+
"command": [
|
|
10
|
+
"python",
|
|
11
|
+
"/workload/workload.py",
|
|
12
|
+
"--device",
|
|
13
|
+
"cpu",
|
|
14
|
+
"--variant",
|
|
15
|
+
"correct"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"candidate": {
|
|
19
|
+
"image": "docker.io/library/python:3.12-slim",
|
|
20
|
+
"command": [
|
|
21
|
+
"python",
|
|
22
|
+
"/workload/workload.py",
|
|
23
|
+
"--device",
|
|
24
|
+
"cpu",
|
|
25
|
+
"--variant",
|
|
26
|
+
"slow"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"workload_file": "workload.py",
|
|
30
|
+
"fixture_file": "fixtures.json",
|
|
31
|
+
"repeats": 3,
|
|
32
|
+
"timeout_seconds": 60,
|
|
33
|
+
"memory_mb": 512,
|
|
34
|
+
"cpus": 2,
|
|
35
|
+
"policy": {
|
|
36
|
+
"min_throughput_ratio": 0.8,
|
|
37
|
+
"max_latency_ratio": 1.3,
|
|
38
|
+
"max_abs_error": 1e-05,
|
|
39
|
+
"max_peak_memory_mb": 1024.0,
|
|
40
|
+
"max_failures": 0,
|
|
41
|
+
"min_samples": 100,
|
|
42
|
+
"max_timing_cv": 0.3
|
|
43
|
+
}
|
|
44
|
+
}
|