touchstone-us 0.1.0__py3-none-any.whl

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.
Files changed (89) hide show
  1. touchstone/__init__.py +1 -0
  2. touchstone/_assets/PROTOCOL.md +92 -0
  3. touchstone/_assets/app.js +151 -0
  4. touchstone/_assets/base.css +128 -0
  5. touchstone/_assets/examples/cpu-correct.json +44 -0
  6. touchstone/_assets/examples/cpu-crash.json +44 -0
  7. touchstone/_assets/examples/cpu-drift.json +44 -0
  8. touchstone/_assets/examples/cpu-missing.json +44 -0
  9. touchstone/_assets/examples/cpu-slow.json +44 -0
  10. touchstone/_assets/examples/cpu-timeout.json +44 -0
  11. touchstone/_assets/examples/cpu-upgrade.json +44 -0
  12. touchstone/_assets/examples/cuda-correct.json +44 -0
  13. touchstone/_assets/examples/cuda-drift.json +44 -0
  14. touchstone/_assets/examples/cuda-slow.json +44 -0
  15. touchstone/_assets/examples/cuda-upgrade.json +44 -0
  16. touchstone/_assets/examples/fixtures.json +651 -0
  17. touchstone/_assets/examples/workload.py +110 -0
  18. touchstone/_assets/fixtures.js +48 -0
  19. touchstone/_assets/index.html +76 -0
  20. touchstone/_assets/responsive.css +21 -0
  21. touchstone/_assets/rl_examples/bad-reference.json +190 -0
  22. touchstone/_assets/rl_examples/broken-control.json +190 -0
  23. touchstone/_assets/rl_examples/cache-leak.json +190 -0
  24. touchstone/_assets/rl_examples/fixed-grader.json +190 -0
  25. touchstone/_assets/rl_examples/malformed-grader.json +190 -0
  26. touchstone/_assets/rl_examples/weak-grader.json +190 -0
  27. touchstone/_assets/styles.css +44 -0
  28. touchstone/_assets/web/demo.js +13 -0
  29. touchstone/_assets/web/docs.css +43 -0
  30. touchstone/_assets/web/docs.html +226 -0
  31. touchstone/_assets/web/index.html +469 -0
  32. touchstone/_assets/web/rl.css +172 -0
  33. touchstone/_assets/web/rl.html +377 -0
  34. touchstone/_assets/web/rl.js +741 -0
  35. touchstone/_assets/web/safety-public.html +38 -0
  36. touchstone/_assets/web/safety.css +119 -0
  37. touchstone/_assets/web/safety.html +70 -0
  38. touchstone/_assets/web/safety.js +481 -0
  39. touchstone/_assets/web/workspace.css +888 -0
  40. touchstone/_assets/web/workspace.js +688 -0
  41. touchstone/agent.py +423 -0
  42. touchstone/app.py +272 -0
  43. touchstone/artifacts.py +31 -0
  44. touchstone/attest.py +178 -0
  45. touchstone/catalog.py +67 -0
  46. touchstone/cli.py +184 -0
  47. touchstone/compare.py +271 -0
  48. touchstone/doctor.py +218 -0
  49. touchstone/models.py +158 -0
  50. touchstone/packages.py +43 -0
  51. touchstone/redact.py +68 -0
  52. touchstone/rl/__init__.py +1 -0
  53. touchstone/rl/analyze.py +330 -0
  54. touchstone/rl/answer.py +391 -0
  55. touchstone/rl/api.py +118 -0
  56. touchstone/rl/attacks.py +116 -0
  57. touchstone/rl/catalog.py +72 -0
  58. touchstone/rl/cli.py +209 -0
  59. touchstone/rl/diff.py +147 -0
  60. touchstone/rl/engine.py +380 -0
  61. touchstone/rl/harnesses/answer.py +97 -0
  62. touchstone/rl/harnesses/grade.py +102 -0
  63. touchstone/rl/harnesses/invoke.py +16 -0
  64. touchstone/rl/models.py +321 -0
  65. touchstone/rl/onboard.py +234 -0
  66. touchstone/rl/service.py +266 -0
  67. touchstone/runner.py +351 -0
  68. touchstone/safety/__init__.py +1 -0
  69. touchstone/safety/adapters.py +108 -0
  70. touchstone/safety/api.py +71 -0
  71. touchstone/safety/cli.py +166 -0
  72. touchstone/safety/codex.py +73 -0
  73. touchstone/safety/compare.py +35 -0
  74. touchstone/safety/demo.py +58 -0
  75. touchstone/safety/engine.py +146 -0
  76. touchstone/safety/execution.py +18 -0
  77. touchstone/safety/generator.py +42 -0
  78. touchstone/safety/generator_worker.py +7 -0
  79. touchstone/safety/models.py +137 -0
  80. touchstone/safety/store.py +244 -0
  81. touchstone/safety/sync.py +64 -0
  82. touchstone/safety/worker.py +31 -0
  83. touchstone/service.py +329 -0
  84. touchstone/store.py +206 -0
  85. touchstone_us-0.1.0.dist-info/METADATA +9 -0
  86. touchstone_us-0.1.0.dist-info/RECORD +89 -0
  87. touchstone_us-0.1.0.dist-info/WHEEL +4 -0
  88. touchstone_us-0.1.0.dist-info/entry_points.txt +3 -0
  89. touchstone_us-0.1.0.dist-info/licenses/LICENSE +40 -0
touchstone/__init__.py ADDED
@@ -0,0 +1 @@
1
+ """Local, evidence-first release qualification."""
@@ -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
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "schema_version": 1,
3
+ "name": "CPU / Injected timeout",
4
+ "description": "Deliberately hangs. The controller must stop its own container and retain evidence.",
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
+ "timeout"
27
+ ]
28
+ },
29
+ "workload_file": "workload.py",
30
+ "fixture_file": "fixtures.json",
31
+ "repeats": 3,
32
+ "timeout_seconds": 10,
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 / Real runtime upgrade",
4
+ "description": "Actual image-version comparison with the same owned classifier fixture. No defect is intentionally injected; this is a small smoke qualification.",
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.13-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
+ }