@microck/raft 0.0.0-stage → 0.2.1

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 (67) hide show
  1. package/.github/assets/raft-logo.png +0 -0
  2. package/LICENSE +21 -0
  3. package/README.md +167 -2
  4. package/deploy/benchmark-boot.py +150 -0
  5. package/deploy/build-image.py +95 -0
  6. package/deploy/deploy.py +176 -0
  7. package/deploy/incus-network.conf +4 -0
  8. package/deploy/install-incus.sh +22 -0
  9. package/deploy/raft-expire.py +62 -0
  10. package/deploy/raft-expire.service +8 -0
  11. package/deploy/raft-expire.timer +8 -0
  12. package/deploy/raft-network.service +12 -0
  13. package/deploy/raft-network.sh +40 -0
  14. package/deploy/verify-controls.py +241 -0
  15. package/deploy/verify-features.py +519 -0
  16. package/deploy/verify-fresh-host.py +301 -0
  17. package/deploy/verify-image-tests.py +139 -0
  18. package/deploy/verify-image.py +95 -0
  19. package/deploy/verify-limits.py +110 -0
  20. package/deploy/verify-live.py +903 -0
  21. package/deploy/verify-release.py +132 -0
  22. package/deploy/verify-tools.py +105 -0
  23. package/docs/benchmarks/amd64-native-ci.json +137 -0
  24. package/docs/benchmarks/arm64-baseline-a.json +108 -0
  25. package/docs/benchmarks/arm64-baseline-b.json +108 -0
  26. package/docs/benchmarks/arm64-candidate-a.json +109 -0
  27. package/docs/benchmarks/arm64-desktop-local.json +22 -0
  28. package/docs/benchmarks/arm64-native-ci.json +137 -0
  29. package/docs/boat-capabilities.md +64 -0
  30. package/docs/boat-parity-design.md +26 -0
  31. package/docs/boot-performance.mdx +102 -0
  32. package/docs/contract.md +93 -0
  33. package/docs/first-box.mdx +86 -0
  34. package/docs/guides/background-jobs.mdx +95 -0
  35. package/docs/guides/backup-recovery.mdx +111 -0
  36. package/docs/guides/desktop-services.mdx +90 -0
  37. package/docs/guides/docker.mdx +84 -0
  38. package/docs/guides/files.mdx +91 -0
  39. package/docs/guides/long-running-services.mdx +109 -0
  40. package/docs/guides/meta.json +18 -0
  41. package/docs/guides/project-setup.mdx +112 -0
  42. package/docs/guides/scripting-ci.mdx +133 -0
  43. package/docs/guides/snapshots-forks.mdx +107 -0
  44. package/docs/guides/troubleshooting.mdx +152 -0
  45. package/docs/guides/upgrades.mdx +113 -0
  46. package/docs/incus.example.json +3 -0
  47. package/docs/index.mdx +40 -0
  48. package/docs/meta.json +21 -0
  49. package/docs/operations.mdx +239 -0
  50. package/docs/publishing.md +48 -0
  51. package/docs/reference/capacity-limits.mdx +92 -0
  52. package/docs/reference/cli.md +288 -0
  53. package/docs/reference/configuration.mdx +77 -0
  54. package/docs/reference/meta.json +10 -0
  55. package/docs/releases/0.2.0.md +22 -0
  56. package/docs/releases/0.2.1.md +14 -0
  57. package/docs/requirements.mdx +47 -0
  58. package/docs/reviews/code-review-2026-10-06.md +168 -0
  59. package/docs/site-development.md +80 -0
  60. package/docs/verification.mdx +237 -0
  61. package/images/incus/build.sh +57 -0
  62. package/images/incus/desktop.sh +21 -0
  63. package/images/incus/raft-desktop.service +7 -0
  64. package/package.json +46 -4
  65. package/raft.py +961 -0
  66. package/raft_files.py +134 -0
  67. package/skills/raft-cli/SKILL.md +117 -0
@@ -0,0 +1,132 @@
1
+ """Inspect built release artifacts for local metadata and private path leakage.
2
+
3
+ This complements a secret scanner and manual history review. It is not a proof
4
+ that every possible personal identifier has been removed.
5
+ """
6
+
7
+ import json
8
+ from pathlib import Path, PurePosixPath
9
+ import re
10
+ import subprocess
11
+ import sys
12
+ import tempfile
13
+ import tarfile
14
+ import zipfile
15
+
16
+ ROOT = Path(__file__).resolve().parent.parent
17
+ sys.path.insert(0, str(ROOT))
18
+ from raft import __version__ # noqa: E402
19
+
20
+ FORBIDDEN = {".git", ".jj", ".venv", ".ruff_cache", "__pycache__"}
21
+ PRIVATE_TEXT = re.compile(r"/(?:home|Users)/[^\s<>]+|[\w.+-]+@[\w.-]+\.[A-Za-z]{2,}")
22
+
23
+
24
+ def inspect(name, content):
25
+ path = PurePosixPath(name)
26
+ if path.is_absolute() or ".." in path.parts or FORBIDDEN.intersection(path.parts):
27
+ raise ValueError("Private metadata or unsafe archive member: " + name)
28
+ if path.suffix == ".pyc":
29
+ raise ValueError("Compiled cache in release: " + name)
30
+ # Source archives also contain binary branding assets; scan their readable bytes.
31
+ match = PRIVATE_TEXT.search(content.decode("utf-8", errors="replace"))
32
+ if match:
33
+ raise ValueError("Private path or email in release member: " + name)
34
+
35
+
36
+ def verify_cli(executable, directory):
37
+ version = subprocess.check_output([str(executable), "--version"], cwd=directory, text=True)
38
+ if version.strip() != __version__:
39
+ raise ValueError("Installed CLI version differs from release source")
40
+ for command in [["--help"], ["upload", "--help"], ["new", "--help"], ["prune", "--help"]]:
41
+ output = subprocess.check_output([str(executable), *command], cwd=directory, text=True)
42
+ if command[0] == "upload" and "--recursive" not in output:
43
+ raise ValueError("Installed CLI lacks recursive transfers")
44
+ if command[0] == "new" and "--disposable" not in output:
45
+ raise ValueError("Installed CLI lacks disposable lifecycle")
46
+ invalid = subprocess.run([str(executable), "new", "--from"], cwd=directory, capture_output=True)
47
+ if invalid.returncode != 2:
48
+ raise ValueError("Installed CLI did not preserve argument-error exit status")
49
+
50
+
51
+ def verify_npm():
52
+ metadata = json.loads((ROOT / "package.json").read_text())
53
+ if metadata["version"] != __version__:
54
+ raise ValueError("npm version differs from Python release version")
55
+ packed = json.loads(
56
+ subprocess.check_output(
57
+ ["npm", "pack", "--json", "--ignore-scripts", "--pack-destination", str(ROOT / "dist")],
58
+ cwd=ROOT,
59
+ text=True,
60
+ )
61
+ )[0]
62
+ package = ROOT / "dist" / packed["filename"]
63
+ with tarfile.open(package) as archive:
64
+ names = set()
65
+ for member in archive.getmembers():
66
+ if not member.isfile():
67
+ raise ValueError("Unexpected npm archive member: " + member.name)
68
+ content = archive.extractfile(member).read()
69
+ inspect(member.name, content)
70
+ names.add(member.name)
71
+ if member.name in {"package/raft.py", "package/raft_files.py"}:
72
+ if content != (ROOT / PurePosixPath(member.name).name).read_bytes():
73
+ raise ValueError("npm runtime differs from canonical Python source")
74
+ required = {
75
+ "package/raft.py",
76
+ "package/raft_files.py",
77
+ "package/LICENSE",
78
+ "package/deploy/deploy.py",
79
+ "package/images/incus/build.sh",
80
+ "package/docs/incus.example.json",
81
+ "package/skills/raft-cli/SKILL.md",
82
+ }
83
+ if not required <= names:
84
+ raise ValueError("npm package lacks required runtime files")
85
+ with tempfile.TemporaryDirectory(prefix="raft-npm-") as work:
86
+ subprocess.run(
87
+ ["npm", "install", "--global", "--prefix", work, "--ignore-scripts", str(package)],
88
+ cwd=work,
89
+ check=True,
90
+ capture_output=True,
91
+ )
92
+ verify_cli(Path(work) / "bin/raft", work)
93
+ print("npm archive and isolated executable installation passed")
94
+
95
+
96
+ def main():
97
+ sources = list((ROOT / "dist").glob("*.tar.gz"))
98
+ wheels = list((ROOT / "dist").glob("*.whl"))
99
+ if len(sources) != 1 or len(wheels) != 1:
100
+ raise ValueError("Build exactly one source archive and wheel before checking")
101
+ with tarfile.open(sources[0]) as archive:
102
+ members = archive.getmembers()
103
+ for member in members:
104
+ if not member.isfile():
105
+ raise ValueError("Unexpected non-file member: " + member.name)
106
+ inspect(member.name, archive.extractfile(member).read())
107
+ names = {PurePosixPath(member.name).parts[1] for member in members}
108
+ if not {"raft.py", "deploy", "docs", "images", "skills", "LICENSE"} <= names:
109
+ raise ValueError("Source archive missing installation resources")
110
+ with zipfile.ZipFile(wheels[0]) as archive:
111
+ for name in archive.namelist():
112
+ inspect(name, archive.read(name))
113
+ if not {"raft.py", "raft_files.py"} <= set(archive.namelist()):
114
+ raise ValueError("Wheel missing CLI module")
115
+ # A new environment avoids both editable checkouts and uv's cached same-version
116
+ # tool environments. Run the installed entry point outside the source tree.
117
+ with tempfile.TemporaryDirectory(prefix="raft-wheel-") as work:
118
+ environment = Path(work) / "venv"
119
+ python = environment / "bin/python"
120
+ subprocess.run(["uv", "venv", "--python", sys.executable, str(environment)], check=True)
121
+ subprocess.run(
122
+ ["uv", "pip", "install", "--no-cache", "--python", str(python), str(wheels[0])],
123
+ check=True,
124
+ )
125
+ verify_cli(environment / "bin/raft", work)
126
+ subprocess.run([str(python), "-I", "-c", "import raft, raft_files"], cwd=work, check=True)
127
+ verify_npm()
128
+ print("Release archives and isolated wheel installation passed")
129
+
130
+
131
+ if __name__ == "__main__":
132
+ main()
@@ -0,0 +1,105 @@
1
+ """Execute real language programs as the guest developer, without model calls."""
2
+
3
+ import argparse
4
+ import json
5
+ from pathlib import Path
6
+ import sys
7
+
8
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
9
+ from raft import execute, instance, parse_handle # noqa: E402
10
+
11
+ PROBE = r"""
12
+ import json, os, subprocess, tempfile
13
+ from pathlib import Path
14
+
15
+ checks = {
16
+ "node": ["node", "-e", "console.log('raft-tool-ok')"],
17
+ "npm": ["bash", "-ec", "cd npm-project; npm install --offline --ignore-scripts; npm run proof"],
18
+ "pnpm": ["bash", "-ec", "cd pnpm-project; pnpm install --offline --ignore-scripts; pnpm run proof"],
19
+ "bun": ["bun", "-e", "console.log('raft-tool-ok')"],
20
+ "deno": ["deno", "eval", "console.log('raft-tool-ok')"],
21
+ "python": ["python3", "-c", "import ssl,sqlite3,venv; print('raft-tool-ok')"],
22
+ "uv": ["bash", "-ec", "uv venv --no-project venv; venv/bin/python -c \"print('raft-tool-ok')\""],
23
+ "go": ["bash", "-ec", "go build -o hello-go hello.go; ./hello-go"],
24
+ "rust": ["bash", "-ec", "rustc hello.rs -o hello-rust; ./hello-rust"],
25
+ "cargo": ["cargo", "run", "--offline", "--quiet", "--manifest-path", "cargo-project/Cargo.toml"],
26
+ "java": ["bash", "-ec", "javac Hello.java; java Hello"],
27
+ "maven": ["bash", "-ec", "mvn -q -f maven-project/pom.xml package; java -cp maven-project/target/classes Hello"],
28
+ "gradle": ["gradle", "--no-daemon", "--console=plain", "-p", "gradle-project", "proof"],
29
+ "kotlin": ["bash", "-ec", "kotlinc hello.kt -include-runtime -d hello-kotlin.jar; java -jar hello-kotlin.jar"],
30
+ "scala": ["bash", "-ec", "scalac Hello.scala; scala -nc HelloScala"],
31
+ "ruby": ["ruby", "-e", "puts 'raft-tool-ok'"],
32
+ "bundler": ["bash", "-ec", "export BUNDLE_GEMFILE=$PWD/bundler-project/Gemfile; bundle install --local; bundle exec ruby -e \"puts 'raft-tool-ok'\""],
33
+ "php": ["php", "-r", "echo 'raft-tool-ok';"],
34
+ "composer": ["composer", "--working-dir=composer-project", "run", "proof"],
35
+ "elixir": ["elixir", "-e", 'IO.puts("raft-tool-ok")'],
36
+ "R": ["Rscript", "-e", 'cat("raft-tool-ok")'],
37
+ "gcc": ["bash", "-ec", "gcc hello.c -o hello-c; ./hello-c"],
38
+ "clang": ["bash", "-ec", "clang hello.c -o hello-clang; ./hello-clang"],
39
+ "cpp": ["bash", "-ec", "g++ hello.cpp -o hello-cpp; ./hello-cpp"],
40
+ "cmake-ninja": ["bash", "-ec", "cmake -S . -B build -G Ninja; cmake --build build; build/hello"],
41
+ "dotnet": ["bash", "-ec", "dotnet new console -o dotnet --no-restore; printf 'Console.WriteLine(\"raft-tool-ok\");' > dotnet/Program.cs; mkdir feed; dotnet restore dotnet --source \"$PWD/feed\"; dotnet run --project dotnet --no-restore"],
42
+ "git": ["bash", "-ec", "git init -q repo; git -C repo status --porcelain"],
43
+ "rg": ["rg", "raft-tool-ok", "hello.c"],
44
+ "jq": ["bash", "-ec", "printf '{\"ok\":true}' | jq -e .ok"],
45
+ "ffmpeg": ["ffmpeg", "-v", "error", "-f", "lavfi", "-i", "color=c=black:s=16x16:d=0.1", "-f", "null", "-"],
46
+ "chromium": ["chromium", "--headless", "--disable-dev-shm-usage", "--dump-dom", "data:text/html,<h1>raft-tool-ok</h1>"],
47
+ }
48
+ sources = {
49
+ "hello.go": 'package main\nimport "fmt"\nfunc main(){fmt.Println("raft-tool-ok")}\n',
50
+ "hello.rs": 'fn main(){println!("raft-tool-ok");}\n',
51
+ "Hello.java": 'public class Hello {public static void main(String[] args){System.out.println("raft-tool-ok");}}\n',
52
+ "hello.kt": 'fun main(){println("raft-tool-ok")}\n',
53
+ "Hello.scala": 'object HelloScala extends App {println("raft-tool-ok")}\n',
54
+ "hello.c": '#include <stdio.h>\nint main(){puts("raft-tool-ok");return 0;}\n',
55
+ "hello.cpp": '#include <iostream>\nint main(){std::cout << "raft-tool-ok";}\n',
56
+ "npm-project/package.json": json.dumps({"name": "raft-npm-proof", "version": "1.0.0", "scripts": {"proof": "node -e \"console.log('raft-tool-ok')\""}}),
57
+ "pnpm-project/package.json": json.dumps({"name": "raft-pnpm-proof", "version": "1.0.0", "scripts": {"proof": "node -e \"console.log('raft-tool-ok')\""}}),
58
+ "cargo-project/Cargo.toml": '[package]\nname="raft-proof"\nversion="0.1.0"\nedition="2021"\n',
59
+ "cargo-project/src/main.rs": 'fn main(){println!("raft-tool-ok");}\n',
60
+ "maven-project/pom.xml": '<project><modelVersion>4.0.0</modelVersion><groupId>dev.raft</groupId><artifactId>proof</artifactId><version>1</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties></project>',
61
+ "maven-project/src/main/java/Hello.java": 'public class Hello {public static void main(String[] args){System.out.println("raft-tool-ok");}}\n',
62
+ "gradle-project/build.gradle": "apply plugin: 'java'\ntask proof(type: JavaExec) { dependsOn classes; main = 'Hello'; classpath = sourceSets.main.runtimeClasspath }\n",
63
+ "gradle-project/src/main/java/Hello.java": 'public class Hello {public static void main(String[] args){System.out.println("raft-tool-ok");}}\n',
64
+ "bundler-project/Gemfile": 'source "https://rubygems.org"\n',
65
+ "composer-project/composer.json": json.dumps({"name": "raft/proof", "scripts": {"proof": "php -r \"echo 'raft-tool-ok';\""}}),
66
+ "CMakeLists.txt": 'cmake_minimum_required(VERSION 3.10)\nproject(hello C)\nadd_executable(hello hello.c)\n',
67
+ }
68
+ # These three commands validate state or decode media rather than print the program marker.
69
+ proof_tools = checks.keys() - {'git', 'jq', 'ffmpeg'}
70
+ report = {}
71
+ with tempfile.TemporaryDirectory(prefix='raft-tool-audit-') as work:
72
+ for filename, content in sources.items():
73
+ source = Path(work) / filename
74
+ source.parent.mkdir(parents=True, exist_ok=True)
75
+ source.write_text(content)
76
+ environment = {**os.environ, 'DOTNET_CLI_TELEMETRY_OPTOUT': '1', 'DOTNET_NOLOGO': '1'}
77
+ for tool, command in checks.items():
78
+ try:
79
+ result = subprocess.run(command, cwd=work, env=environment, capture_output=True, text=True, timeout=120)
80
+ report[tool] = {'passed': result.returncode == 0 and (tool not in proof_tools or 'raft-tool-ok' in result.stdout), 'exitCode': result.returncode,
81
+ 'output': (result.stdout + result.stderr)[-2000:]}
82
+ except (OSError, subprocess.TimeoutExpired) as error:
83
+ report[tool] = {'passed': False, 'output': str(error)}
84
+ print(json.dumps(report))
85
+ """
86
+
87
+
88
+ def main():
89
+ parser = argparse.ArgumentParser(description=__doc__)
90
+ parser.add_argument("box")
91
+ args = parser.parse_args()
92
+ location, name = parse_handle(args.box)
93
+ instance(location, name)
94
+ response = execute(
95
+ location, name, ["runuser", "-u", "developer", "--", "python3", "-c", PROBE], capture=True
96
+ )
97
+ if response.returncode:
98
+ raise RuntimeError(response.stderr.decode().strip())
99
+ report = json.loads(response.stdout)
100
+ print(json.dumps(report, indent=2))
101
+ return int(any(not check["passed"] for check in report.values()))
102
+
103
+
104
+ if __name__ == "__main__":
105
+ sys.exit(main())
@@ -0,0 +1,137 @@
1
+ {
2
+ "hostArchitecture": "x86_64",
3
+ "hostCpus": 4,
4
+ "guestCpus": 1,
5
+ "guestMemory": "2GiB",
6
+ "sshRoundTripSeconds": 0.252,
7
+ "scope": "Cached local image; includes controller CLI and SSH; no host reboot or download",
8
+ "samples": [
9
+ {
10
+ "create": {
11
+ "cliReturnSeconds": 0.692,
12
+ "commandReadySeconds": 1.375,
13
+ "dockerReadySeconds": 3.035,
14
+ "desktopStartSeconds": 1.604
15
+ },
16
+ "resume": {
17
+ "cliReturnSeconds": 0.81,
18
+ "commandReadySeconds": 1.477,
19
+ "dockerReadySeconds": 3.049,
20
+ "desktopStartSeconds": 1.587
21
+ }
22
+ },
23
+ {
24
+ "create": {
25
+ "cliReturnSeconds": 0.648,
26
+ "commandReadySeconds": 1.324,
27
+ "dockerReadySeconds": 3.131,
28
+ "desktopStartSeconds": 1.627
29
+ },
30
+ "resume": {
31
+ "cliReturnSeconds": 0.858,
32
+ "commandReadySeconds": 1.556,
33
+ "dockerReadySeconds": 2.995,
34
+ "desktopStartSeconds": 1.595
35
+ }
36
+ },
37
+ {
38
+ "create": {
39
+ "cliReturnSeconds": 0.659,
40
+ "commandReadySeconds": 1.334,
41
+ "dockerReadySeconds": 3.044,
42
+ "desktopStartSeconds": 1.592
43
+ },
44
+ "resume": {
45
+ "cliReturnSeconds": 0.803,
46
+ "commandReadySeconds": 1.489,
47
+ "dockerReadySeconds": 3.196,
48
+ "desktopStartSeconds": 1.567
49
+ }
50
+ },
51
+ {
52
+ "create": {
53
+ "cliReturnSeconds": 0.707,
54
+ "commandReadySeconds": 1.396,
55
+ "dockerReadySeconds": 2.815,
56
+ "desktopStartSeconds": 1.567
57
+ },
58
+ "resume": {
59
+ "cliReturnSeconds": 0.836,
60
+ "commandReadySeconds": 1.542,
61
+ "dockerReadySeconds": 3.204,
62
+ "desktopStartSeconds": 1.574
63
+ }
64
+ },
65
+ {
66
+ "create": {
67
+ "cliReturnSeconds": 0.653,
68
+ "commandReadySeconds": 1.434,
69
+ "dockerReadySeconds": 2.916,
70
+ "desktopStartSeconds": 1.578
71
+ },
72
+ "resume": {
73
+ "cliReturnSeconds": 0.822,
74
+ "commandReadySeconds": 1.475,
75
+ "dockerReadySeconds": 2.685,
76
+ "desktopStartSeconds": 1.57
77
+ }
78
+ }
79
+ ],
80
+ "imageVolumeCachedAtStart": true,
81
+ "guestArchitecture": "amd64",
82
+ "imageSizeBytes": 1992633951,
83
+ "summary": {
84
+ "create": {
85
+ "cliReturnSeconds": {
86
+ "median": 0.659,
87
+ "min": 0.648,
88
+ "max": 0.707,
89
+ "p95": 0.707
90
+ },
91
+ "commandReadySeconds": {
92
+ "median": 1.375,
93
+ "min": 1.324,
94
+ "max": 1.434,
95
+ "p95": 1.434
96
+ },
97
+ "dockerReadySeconds": {
98
+ "median": 3.035,
99
+ "min": 2.815,
100
+ "max": 3.131,
101
+ "p95": 3.131
102
+ },
103
+ "desktopStartSeconds": {
104
+ "median": 1.592,
105
+ "min": 1.567,
106
+ "max": 1.627,
107
+ "p95": 1.627
108
+ }
109
+ },
110
+ "resume": {
111
+ "cliReturnSeconds": {
112
+ "median": 0.822,
113
+ "min": 0.803,
114
+ "max": 0.858,
115
+ "p95": 0.858
116
+ },
117
+ "commandReadySeconds": {
118
+ "median": 1.489,
119
+ "min": 1.475,
120
+ "max": 1.556,
121
+ "p95": 1.556
122
+ },
123
+ "dockerReadySeconds": {
124
+ "median": 3.049,
125
+ "min": 2.685,
126
+ "max": 3.204,
127
+ "p95": 3.204
128
+ },
129
+ "desktopStartSeconds": {
130
+ "median": 1.574,
131
+ "min": 1.567,
132
+ "max": 1.595,
133
+ "p95": 1.595
134
+ }
135
+ }
136
+ }
137
+ }
@@ -0,0 +1,108 @@
1
+ {
2
+ "hostArchitecture": "aarch64",
3
+ "hostCpus": 2,
4
+ "guestCpus": 1,
5
+ "guestMemory": "2GiB",
6
+ "sshRoundTripSeconds": 0.397,
7
+ "scope": "Cached local image; includes controller CLI and SSH; no host reboot or download",
8
+ "samples": [
9
+ {
10
+ "create": {
11
+ "cliReturnSeconds": 0.844,
12
+ "commandReadySeconds": 2.591,
13
+ "dockerReadySeconds": 4.36,
14
+ "desktopStartSeconds": 2.888
15
+ },
16
+ "resume": {
17
+ "cliReturnSeconds": 1.547,
18
+ "commandReadySeconds": 3.907,
19
+ "dockerReadySeconds": 4.959,
20
+ "desktopStartSeconds": 2.305
21
+ }
22
+ },
23
+ {
24
+ "create": {
25
+ "cliReturnSeconds": 0.978,
26
+ "commandReadySeconds": 1.918,
27
+ "dockerReadySeconds": 3.941,
28
+ "desktopStartSeconds": 2.602
29
+ },
30
+ "resume": {
31
+ "cliReturnSeconds": 1.0,
32
+ "commandReadySeconds": 1.804,
33
+ "dockerReadySeconds": 3.917,
34
+ "desktopStartSeconds": 2.492
35
+ }
36
+ },
37
+ {
38
+ "create": {
39
+ "cliReturnSeconds": 0.864,
40
+ "commandReadySeconds": 1.724,
41
+ "dockerReadySeconds": 3.768,
42
+ "desktopStartSeconds": 2.511
43
+ },
44
+ "resume": {
45
+ "cliReturnSeconds": 1.056,
46
+ "commandReadySeconds": 1.851,
47
+ "dockerReadySeconds": 3.296,
48
+ "desktopStartSeconds": 2.43
49
+ }
50
+ }
51
+ ],
52
+ "guestArchitecture": "arm64",
53
+ "imageSizeBytes": 2626705196,
54
+ "summary": {
55
+ "create": {
56
+ "cliReturnSeconds": {
57
+ "median": 0.864,
58
+ "min": 0.844,
59
+ "max": 0.978,
60
+ "p95": 0.978
61
+ },
62
+ "commandReadySeconds": {
63
+ "median": 1.918,
64
+ "min": 1.724,
65
+ "max": 2.591,
66
+ "p95": 2.591
67
+ },
68
+ "dockerReadySeconds": {
69
+ "median": 3.941,
70
+ "min": 3.768,
71
+ "max": 4.36,
72
+ "p95": 4.36
73
+ },
74
+ "desktopStartSeconds": {
75
+ "median": 2.602,
76
+ "min": 2.511,
77
+ "max": 2.888,
78
+ "p95": 2.888
79
+ }
80
+ },
81
+ "resume": {
82
+ "cliReturnSeconds": {
83
+ "median": 1.056,
84
+ "min": 1.0,
85
+ "max": 1.547,
86
+ "p95": 1.547
87
+ },
88
+ "commandReadySeconds": {
89
+ "median": 1.851,
90
+ "min": 1.804,
91
+ "max": 3.907,
92
+ "p95": 3.907
93
+ },
94
+ "dockerReadySeconds": {
95
+ "median": 3.917,
96
+ "min": 3.296,
97
+ "max": 4.959,
98
+ "p95": 4.959
99
+ },
100
+ "desktopStartSeconds": {
101
+ "median": 2.43,
102
+ "min": 2.305,
103
+ "max": 2.492,
104
+ "p95": 2.492
105
+ }
106
+ }
107
+ }
108
+ }
@@ -0,0 +1,108 @@
1
+ {
2
+ "hostArchitecture": "aarch64",
3
+ "hostCpus": 2,
4
+ "guestCpus": 1,
5
+ "guestMemory": "2GiB",
6
+ "sshRoundTripSeconds": 3.556,
7
+ "scope": "Cached local image; includes controller CLI and SSH; no host reboot or download",
8
+ "samples": [
9
+ {
10
+ "create": {
11
+ "cliReturnSeconds": 2.906,
12
+ "commandReadySeconds": 7.408,
13
+ "dockerReadySeconds": 11.445,
14
+ "desktopStartSeconds": 7.344
15
+ },
16
+ "resume": {
17
+ "cliReturnSeconds": 4.224,
18
+ "commandReadySeconds": 8.213,
19
+ "dockerReadySeconds": 11.653,
20
+ "desktopStartSeconds": 7.734
21
+ }
22
+ },
23
+ {
24
+ "create": {
25
+ "cliReturnSeconds": 3.461,
26
+ "commandReadySeconds": 6.936,
27
+ "dockerReadySeconds": 10.753,
28
+ "desktopStartSeconds": 7.631
29
+ },
30
+ "resume": {
31
+ "cliReturnSeconds": 3.889,
32
+ "commandReadySeconds": 7.234,
33
+ "dockerReadySeconds": 11.291,
34
+ "desktopStartSeconds": 6.876
35
+ }
36
+ },
37
+ {
38
+ "create": {
39
+ "cliReturnSeconds": 2.219,
40
+ "commandReadySeconds": 6.221,
41
+ "dockerReadySeconds": 10.664,
42
+ "desktopStartSeconds": 7.659
43
+ },
44
+ "resume": {
45
+ "cliReturnSeconds": 3.701,
46
+ "commandReadySeconds": 8.341,
47
+ "dockerReadySeconds": 11.918,
48
+ "desktopStartSeconds": 7.669
49
+ }
50
+ }
51
+ ],
52
+ "guestArchitecture": "arm64",
53
+ "imageSizeBytes": 2626688616,
54
+ "summary": {
55
+ "create": {
56
+ "cliReturnSeconds": {
57
+ "median": 2.906,
58
+ "min": 2.219,
59
+ "max": 3.461,
60
+ "p95": 3.461
61
+ },
62
+ "commandReadySeconds": {
63
+ "median": 6.936,
64
+ "min": 6.221,
65
+ "max": 7.408,
66
+ "p95": 7.408
67
+ },
68
+ "dockerReadySeconds": {
69
+ "median": 10.753,
70
+ "min": 10.664,
71
+ "max": 11.445,
72
+ "p95": 11.445
73
+ },
74
+ "desktopStartSeconds": {
75
+ "median": 7.631,
76
+ "min": 7.344,
77
+ "max": 7.659,
78
+ "p95": 7.659
79
+ }
80
+ },
81
+ "resume": {
82
+ "cliReturnSeconds": {
83
+ "median": 3.889,
84
+ "min": 3.701,
85
+ "max": 4.224,
86
+ "p95": 4.224
87
+ },
88
+ "commandReadySeconds": {
89
+ "median": 8.213,
90
+ "min": 7.234,
91
+ "max": 8.341,
92
+ "p95": 8.341
93
+ },
94
+ "dockerReadySeconds": {
95
+ "median": 11.653,
96
+ "min": 11.291,
97
+ "max": 11.918,
98
+ "p95": 11.918
99
+ },
100
+ "desktopStartSeconds": {
101
+ "median": 7.669,
102
+ "min": 6.876,
103
+ "max": 7.734,
104
+ "p95": 7.734
105
+ }
106
+ }
107
+ }
108
+ }