sandboxedjs 0.2.11 → 0.2.13

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 (48) hide show
  1. package/README.md +21 -9
  2. package/assets/logo.png +0 -0
  3. package/bin/sandboxedjs-egress.mjs +25 -10
  4. package/dist/index.cjs +87 -3
  5. package/dist/index.js +87 -3
  6. package/dist/python/python.data +140 -141
  7. package/dist/python/python.js +1 -1
  8. package/dist/python/python.wasm +0 -0
  9. package/dist/python/runtime.json +3 -3
  10. package/dist/python-worker.js +9 -0
  11. package/dist/service-worker.js +3 -2
  12. package/docs/agent/COMMANDS.md +85 -0
  13. package/docs/agent/DECISION-TREE.md +84 -0
  14. package/docs/agent/INVARIANTS.md +40 -0
  15. package/docs/agent/LAUNCH-PROMPT.md +37 -0
  16. package/docs/agent/LOOP.md +84 -0
  17. package/docs/agent/README.md +77 -0
  18. package/docs/agent/ROADMAP.md +37 -0
  19. package/docs/agent/STATE.md +93 -0
  20. package/docs/agent/tasks/00-verify-inherited-work.md +36 -0
  21. package/docs/agent/tasks/01-authoritative-metadata.md +34 -0
  22. package/docs/agent/tasks/02-native-dependencies.md +35 -0
  23. package/docs/agent/tasks/03-reproducible-inputs.md +27 -0
  24. package/docs/agent/tasks/04-build-frontends.md +27 -0
  25. package/docs/agent/tasks/05-registry-integration.md +27 -0
  26. package/docs/agent/tasks/06-package-cohorts.md +42 -0
  27. package/docs/agent/tasks/07-build-on-miss-boundary.md +31 -0
  28. package/docs/browser-runtime-architecture.md +132 -0
  29. package/docs/compatibility-implementation-plan.md +98 -0
  30. package/docs/developer-tool-packs.md +134 -0
  31. package/docs/frontend-automation.md +49 -0
  32. package/docs/fullstack-deployment.md +163 -0
  33. package/docs/handoff.md +275 -0
  34. package/docs/original-x64.md +39 -0
  35. package/docs/platform-hardening.md +49 -0
  36. package/docs/python/abi.md +97 -0
  37. package/docs/python/architecture.md +94 -0
  38. package/docs/python/baseline-inventory.md +54 -0
  39. package/docs/python/build-on-miss.md +198 -0
  40. package/docs/python/compatibility.md +206 -0
  41. package/docs/python/cross-build.md +354 -0
  42. package/docs/python/extensions.md +282 -0
  43. package/docs/python/release-gates.md +46 -0
  44. package/docs/python/virtual-sockets-plan.md +331 -0
  45. package/docs/runtime-lifecycle-fixes.md +39 -0
  46. package/docs/server-previews.md +268 -0
  47. package/docs/virtual-browser.md +120 -0
  48. package/package.json +6 -3
Binary file
@@ -18,9 +18,9 @@
18
18
  "artifacts": {
19
19
  "moduleUrl": "./python.js",
20
20
  "hashes": {
21
- "python.js": "sha256-ba225e5b4900449d493f213dc67263ed1afa7497f36582c43d778ccc282fe749",
22
- "python.wasm": "sha256-a971913c97e671ec281c92c2922e0c64b3e2c9565c58a466a9dda78df5bb8e7a",
23
- "python.data": "sha256-98d1fd943b6530e6ac7dd816420efe81082510da14c49bdc06fa60f5b08b924e",
21
+ "python.js": "sha256-2077b7c944097fa32fd80ffdd2575d5877a75bea77a0083f3dce93e7d2ab2976",
22
+ "python.wasm": "sha256-03f5cb9889a26d5f0b5a3e9d7310e2c5d9f2e8d1c4f9673b061ee19fcbe759c1",
23
+ "python.data": "sha256-c6e6bcf4afd43d12b50c6a0d013d400868434bbfd37341d4642ea40ad69cacd3",
24
24
  "python.worker.js": "sha256-63bb1df52c4e3a95eae7b2d77c98554188fcc5925e72628ea0c34d5c573977a5"
25
25
  }
26
26
  },
@@ -802,6 +802,7 @@ async function runPythonProcess(start, port) {
802
802
  )).default;
803
803
  let exitCode = 0;
804
804
  let guestMemory;
805
+ let threadBridgeName;
805
806
  const guestHeap = () => {
806
807
  const exported = config.HEAPU8;
807
808
  if (exported && exported.byteLength > 0) return exported;
@@ -886,6 +887,7 @@ async function runPythonProcess(start, port) {
886
887
  if (!guestMemory && result.instance.exports.memory instanceof WebAssembly.Memory) {
887
888
  guestMemory = result.instance.exports.memory;
888
889
  }
890
+ threadBridgeName = result.instance.exports.sbx_thread_bridge_name;
889
891
  receiveInstance(result.instance, result.module);
890
892
  } catch (error) {
891
893
  config.onAbort?.(error);
@@ -903,6 +905,13 @@ async function runPythonProcess(start, port) {
903
905
  mountContainer(config.FS, client, start.mounts, config.ERRNO_CODES ?? {});
904
906
  bindStdio(config.FS, client, start.isTty);
905
907
  for (const [key, value] of Object.entries(start.env)) config.ENV[key] = value;
908
+ if (start.threadChannel && typeof threadBridgeName === "function") {
909
+ const bytes = new TextEncoder().encode(start.threadChannel + "\0");
910
+ if (bytes.length > 128) throw new Error("Python thread channel name is too long");
911
+ guestHeap().set(bytes, threadBridgeName());
912
+ port.postMessage({ type: "thread-memory", memory: guestMemory });
913
+ config.ENV.SBX_THREAD_HOST_CALLS = "1";
914
+ }
906
915
  try {
907
916
  config.FS.chdir(start.cwd);
908
917
  } catch {
@@ -530,7 +530,8 @@ var PreviewRouter = class {
530
530
  this.options.onStale?.(clientId);
531
531
  }
532
532
  const headers = new Headers(result.headers);
533
- const body = this.options.injectSockets === false ? result.body : withSockets(result.body, headers);
533
+ const bodyless = request.method === "HEAD" || [204, 205, 304].includes(result.status);
534
+ const body = bodyless ? null : this.options.injectSockets === false ? result.body : withSockets(result.body, headers);
534
535
  headers.set("Cross-Origin-Resource-Policy", "cross-origin");
535
536
  headers.set("Cross-Origin-Embedder-Policy", "require-corp");
536
537
  return new Response(body, { status: result.status, statusText: result.statusText, headers });
@@ -656,7 +657,7 @@ worker.addEventListener("fetch", (event) => {
656
657
  const claimed = router.claimedPort(url.pathname);
657
658
  if (claimed !== null && event.request.mode === "navigate") {
658
659
  router.bind(event.resultingClientId || event.clientId, claimed);
659
- event.respondWith(router.fetch(claimed, "/", event.request, event.resultingClientId || event.clientId));
660
+ event.respondWith(router.fetch(claimed, router.containerPath(url.pathname, url.search), event.request, event.resultingClientId || event.clientId));
660
661
  return;
661
662
  }
662
663
  const port = router.portForRequest(url.pathname, event.clientId);
@@ -0,0 +1,85 @@
1
+ # Command catalog
2
+
3
+ Run commands from `/Users/shazi/Projects/SandboxedJs` unless stated otherwise.
4
+ Use focused commands first. Keep long logs out of model context:
5
+
6
+ ```sh
7
+ some-command > /tmp/sbx-native-build.log 2>&1
8
+ tail -n 120 /tmp/sbx-native-build.log
9
+ ```
10
+
11
+ Do not use the redirection form when editing source files; it is for disposable
12
+ logs only.
13
+
14
+ ## Cheap inspection
15
+
16
+ ```sh
17
+ git status --short
18
+ git diff --cached --check
19
+ git diff --cached --stat
20
+ python3 -m json.tool python-runtime/abi/extension-abi.json >/dev/null
21
+ ```
22
+
23
+ ## Build prerequisites and runtime
24
+
25
+ ```sh
26
+ make -C python-runtime doctor
27
+ make -C python-runtime python PROFILE=dynamic
28
+ make -C python-runtime package PROFILE=dynamic
29
+ npm run build
30
+ ```
31
+
32
+ Do not rebuild CPython when the runtime and ABI inputs have not changed and the
33
+ required output already exists.
34
+
35
+ ## Extension fixtures and index
36
+
37
+ ```sh
38
+ python3 python-runtime/scripts/build_extension.py \
39
+ python-runtime/fixtures/sbx_setuptools_probe/recipe.json
40
+ python3 python-runtime/scripts/build_extension.py \
41
+ python-runtime/fixtures/sbx_cython_probe/recipe.json
42
+ python3 python-runtime/scripts/build_extension.py \
43
+ python-runtime/fixtures/sbx_rust_probe/recipe.json
44
+ python3 python-runtime/scripts/build_index.py
45
+ ```
46
+
47
+ If a wheel changes, rebuild `index.json` before runtime tests or its digest will
48
+ correctly be stale.
49
+
50
+ ## Focused tests
51
+
52
+ ```sh
53
+ npx vitest run test/python-runtime/extensions.test.ts
54
+ npx vitest run test/python-runtime/resolver.test.ts
55
+ npx vitest run test/python-runtime/extension-abi.test.ts
56
+ npm run typecheck
57
+ ```
58
+
59
+ Run `npm run check` only at milestone gates. Network-enabled suites are not a
60
+ default native-package check.
61
+
62
+ ## Wheel inspection
63
+
64
+ ```sh
65
+ python3 -m zipfile -l path/to/package.whl
66
+ python3 python-runtime/scripts/build_index.py --wheels path/to/wheel-directory
67
+ ```
68
+
69
+ Prefer adding a small reusable inspection script over repeatedly embedding
70
+ complex Python in shell commands.
71
+
72
+ ## Logs
73
+
74
+ Use one log per active failure under `/tmp`, named with the task and package.
75
+ Keep only:
76
+
77
+ - the exact command;
78
+ - toolchain versions when relevant;
79
+ - first causal error;
80
+ - final 80-150 lines;
81
+ - exit code.
82
+
83
+ Warnings are not tasks unless they identify incorrect output or a future
84
+ failure covered by the current milestone.
85
+
@@ -0,0 +1,84 @@
1
+ # Failure classification and decisions
2
+
3
+ Classify an observed failure by its earliest decisive symptom.
4
+
5
+ ## Resolver says no usable distribution
6
+
7
+ 1. Inspect candidate filenames and tags.
8
+ 2. If a pure wheel exists, fix resolver/tag/metadata behavior; do not compile.
9
+ 3. If a matching SandboxedJS wheel exists, inspect index `abiId`, digest, and
10
+ dependency metadata.
11
+ 4. If only an sdist or host-native wheels exist, route to the external
12
+ cross-builder. Do not let the runtime installer build source yet.
13
+
14
+ ## Build frontend cannot start
15
+
16
+ - Missing host Python module: classify as a build requirement.
17
+ - Unpinned requirement: add an exact version and hash acquisition path.
18
+ - Unsupported backend: add a backend adapter, not a package conditional.
19
+ - Network failure: preserve the command and request network approval; do not
20
+ substitute an unverified archive.
21
+
22
+ ## Compiler uses host headers or compiler
23
+
24
+ - Inspect generated cross-sysconfig and command line.
25
+ - Fix host/target environment separation.
26
+ - Never solve this by renaming a produced artifact.
27
+
28
+ ## Header or library not found
29
+
30
+ 1. Determine whether it is a Python dependency or a native target library.
31
+ 2. For a target library, require a declared, pinned native dependency.
32
+ 3. Build it into the ABI/profile-specific sysroot.
33
+ 4. Expose sysroot include/library paths through the cross environment.
34
+ 5. Add a reduced fixture proving the dependency mechanism before retrying a
35
+ large real package.
36
+
37
+ ## Configure test compiles, then tries to execute
38
+
39
+ This is a cross-compilation probe problem. Prefer, in order:
40
+
41
+ 1. upstream-supported cross-file/cache variables;
42
+ 2. a generic build-backend cross configuration;
43
+ 3. a visible package patch providing the target fact.
44
+
45
+ Never execute target WebAssembly as if it were a host binary. If executing a
46
+ probe under a controlled runner is proposed, stop for architectural review.
47
+
48
+ ## Linker failure
49
+
50
+ - Missing `Py*` symbols can remain unresolved in a side module if supplied by
51
+ the main module; confirm rather than blindly adding `-lpython`.
52
+ - Missing native-library symbols require target dependency/link-order work.
53
+ - Shared-memory, PIC, exception, relocation, or atomics errors are ABI issues;
54
+ inspect `INVARIANTS.md` and escalate before changing flags.
55
+ - Duplicate symbols often indicate a static library linked twice; inspect the
56
+ complete link line.
57
+
58
+ ## Wheel builds but validation fails
59
+
60
+ - Not `\0asm`: host compiler leakage.
61
+ - No `dylink`: side-module link mode was lost.
62
+ - Missing `PyInit_*`: module naming/export problem.
63
+ - Wrong tag or ABI: wheel construction problem. Rebuild; never retag.
64
+
65
+ ## Install succeeds but import fails
66
+
67
+ - Missing Python wrapper files: wheel assembly/layout defect.
68
+ - Missing dependent shared/static symbols: target dependency closure defect.
69
+ - Init symbol mismatch: derive the module name from installed path.
70
+ - Trap, memory corruption, or exception failure: ABI mismatch until disproven.
71
+
72
+ ## Import succeeds but behavior fails
73
+
74
+ Classify whether the package needs an unavailable OS capability, contains a
75
+ 32-bit assumption, exceeds memory, or has a package defect. Record an honest
76
+ compatibility limitation when the platform capability is genuinely absent.
77
+
78
+ ## Test hangs
79
+
80
+ Do not immediately increase timeouts. Determine whether the process is waiting
81
+ on input, network, a child process, a pthread, or a host ABI response. Capture a
82
+ bounded stack/process snapshot where possible. Kill only the exact process you
83
+ started.
84
+
@@ -0,0 +1,40 @@
1
+ # Non-negotiable invariants
2
+
3
+ Read this before changing ABI, wheel, resolver, or compiler behavior.
4
+
5
+ 1. `python-runtime/abi/extension-abi.json` is the source of truth for target
6
+ identity and compile/link compatibility. Recipes cannot override ABI flags.
7
+ 2. A host-native ELF, Mach-O, `.node`, or other binary is never accepted or
8
+ relabeled as WebAssembly.
9
+ 3. A native wheel must match both its Python wheel tag and SandboxedJS
10
+ `abiId`.
11
+ 4. Build tools run on the build machine. Target code and target libraries are
12
+ compiled for wasm32. Never put target artifacts on the host interpreter's
13
+ import path.
14
+ 5. Build, host, Python-runtime, and native-target dependencies are separate
15
+ concepts and must be represented separately.
16
+ 6. Sources and build-tool artifacts are version-pinned and hash-verifiable.
17
+ 7. Generic behavior lives in generic machinery. Package-specific behavior is
18
+ visible in a recipe and/or patch, never hidden behind `if package == ...`.
19
+ 8. The package's own metadata is authoritative. Recipes may constrain or add
20
+ target facts, but must not silently duplicate drifting `Requires-Dist` data.
21
+ 9. Installer operations remain transactional. Failed resolution, download, or
22
+ installation must not leave a partial environment.
23
+ 10. A build is supported only after the wheel installs and its compiled module
24
+ executes under the owned SandboxedJS CPython runtime.
25
+ 11. Browser compatibility remains mandatory. Runtime TypeScript must not gain
26
+ unconditional Node builtin imports.
27
+ 12. Unsupported operating-system capabilities fail honestly. Package success
28
+ must not be manufactured by fake sockets, fake processes, or silent skips.
29
+
30
+ ## Forbidden shortcuts
31
+
32
+ - Weakening `verify_side_module` or ABI checks to make a fixture pass.
33
+ - Adding arbitrary recipe compiler/link flags.
34
+ - Copying metadata solely from a handwritten recipe when upstream metadata can
35
+ be generated.
36
+ - Installing unpinned build requirements from the network in a release build.
37
+ - Treating "wheel file exists" as an acceptance result.
38
+ - Starting with NumPy-specific branches in the generic pipeline.
39
+ - Running full tests repeatedly when a focused test identifies the defect.
40
+
@@ -0,0 +1,37 @@
1
+ # Prompt to launch or resume Claude Opus
2
+
3
+ Copy the text below into the coding task. Do not paste the rest of this folder
4
+ into the prompt; the agent should read files on demand.
5
+
6
+ ```text
7
+ You are the sole implementation agent for the SandboxedJS native Python
8
+ package platform. The project controller is:
9
+
10
+ agent-projects/python-package-platform/README.md
11
+
12
+ Begin by reading only README.md, STATE.md, and the current task named in
13
+ STATE.md. Follow LOOP.md. Execute commands and make decisions from their actual
14
+ outputs. Continue through tasks while gates pass and context remains healthy.
15
+ Keep STATE.md current so another task can resume without chat history.
16
+
17
+ Preserve all pre-existing and staged work. Do not commit, publish, deploy,
18
+ discard changes, weaken ABI validation, or change the ABI contract unless I
19
+ explicitly authorize it. Use focused tests before broad suites. Keep long build
20
+ logs in /tmp and bring only decisive excerpts into context.
21
+
22
+ If a stop condition in LOOP.md occurs, stop with a compact escalation packet.
23
+ The goal is a general package platform; NumPy is a later acceptance case, not a
24
+ package-specific architecture target.
25
+
26
+ Do not merely review or propose a plan. Work autonomously: inspect, edit,
27
+ execute focused commands, diagnose their outputs, verify exit gates, update
28
+ STATE.md, and advance to the next task. Do not ask for confirmation between
29
+ ordinary in-scope steps. Continue until a documented stop condition requires my
30
+ decision or all roadmap gates are complete.
31
+ ```
32
+
33
+ ## Execution policy
34
+
35
+ This workflow assumes one Claude Opus agent. Do not delegate work to other
36
+ models or create subagents. Use the stop conditions and ask the user for one
37
+ concrete decision only when necessary.
@@ -0,0 +1,84 @@
1
+ # Agent execution loop
2
+
3
+ Use this loop exactly. It is designed for a smaller model that can act well
4
+ when each decision is grounded in the previous command's output.
5
+
6
+ ## 1. Orient
7
+
8
+ Read `README.md`, `STATE.md`, and the current task only. Inspect `git status
9
+ --short` before editing. Treat all pre-existing changes as user-owned.
10
+
11
+ State the current hypothesis in one sentence. A hypothesis must predict an
12
+ observable result, for example: "the linker cannot find `libxml2` because the
13
+ dynamic sysroot is absent from target link flags."
14
+
15
+ ## 2. Choose the cheapest discriminating command
16
+
17
+ Run the smallest command that can disprove the hypothesis. Prefer, in order:
18
+
19
+ 1. static inspection of one relevant file;
20
+ 2. one unit test or one fixture build;
21
+ 3. one runtime import test;
22
+ 4. the focused suite;
23
+ 5. the full suite only at a milestone gate.
24
+
25
+ Never rerun a long build unchanged. If a command failed, inspect its decisive
26
+ error first and change either the hypothesis or the implementation.
27
+
28
+ ## 3. Classify the result
29
+
30
+ Use `DECISION-TREE.md`. Every failure must be classified before code changes.
31
+ If there is not enough evidence, gather more evidence rather than guessing.
32
+
33
+ ## 4. Make one coherent change
34
+
35
+ Change the smallest architectural seam that removes the demonstrated failure
36
+ class. Do not add a package-name conditional to the generic builder. A package
37
+ patch belongs in an explicit recipe patch directory, with a comment explaining
38
+ the upstream assumption it replaces.
39
+
40
+ Use `apply_patch` for hand edits. Do not overwrite files with shell redirects.
41
+ Do not alter generated ABI files directly.
42
+
43
+ ## 5. Verify in layers
44
+
45
+ Run the focused check that failed. If it passes, run the task's exit gate.
46
+ Compilation is never the final gate for an extension: install and import it in
47
+ the owned CPython runtime and exercise at least one native behavior.
48
+
49
+ ## 6. Record and advance
50
+
51
+ Update `STATE.md` with compact evidence. If the task exit gate passes, set its
52
+ checkboxes, point `Current task` to the next task in `ROADMAP.md`, and continue
53
+ if budget remains.
54
+
55
+ ## Stop conditions
56
+
57
+ Stop and request a user decision when:
58
+
59
+ - the next action requires credentials, deployment, paid infrastructure, or
60
+ publishing outside the repository;
61
+ - fulfilling the task requires changing the ABI contract rather than fixing a
62
+ consumer of it;
63
+ - an upstream license is unclear or incompatible;
64
+ - a destructive action, history rewrite, or discard of existing work appears
65
+ necessary;
66
+ - the same failure class survives three evidence-driven attempts;
67
+ - a design choice changes public API or materially increases shipped runtime
68
+ size without an already-stated budget.
69
+
70
+ When stopping, preserve logs and state the smallest exact decision needed.
71
+
72
+ ## Escalation packet for the user
73
+
74
+ When a stop condition is reached, prepare a compact packet containing:
75
+
76
+ - intended invariant;
77
+ - exact command;
78
+ - final 80-150 relevant log lines;
79
+ - files and functions involved;
80
+ - three attempted hypotheses and what disproved each;
81
+ - the decision required.
82
+
83
+ Do not send entire build logs or the full repository history. Wait for the
84
+ user's decision, record it in `STATE.md`, and then resume this same loop.
@@ -0,0 +1,77 @@
1
+ # SandboxedJS native Python package platform
2
+
3
+ This folder is an executable work specification for a coding agent. Its goal is
4
+ not to port NumPy. Its goal is to make native Python packages a platform
5
+ capability of SandboxedJS, with NumPy eventually serving as one demanding
6
+ acceptance case.
7
+
8
+ ## Start here
9
+
10
+ At the beginning of every turn, read only these files:
11
+
12
+ 1. `README.md` (this file).
13
+ 2. `STATE.md`.
14
+ 3. The one task file named by `STATE.md`.
15
+
16
+ Do not reread every document on every turn. Open `INVARIANTS.md`,
17
+ `DECISION-TREE.md`, or `COMMANDS.md` only when the current task points to them
18
+ or an observed failure requires them. This is intentional: the folder is also
19
+ a context and token budget.
20
+
21
+ Then execute the loop in `LOOP.md`. Continue until the current task's exit gate
22
+ passes or a stop condition requires the user or a stronger model.
23
+
24
+ ## Product objective
25
+
26
+ The eventual user experience is:
27
+
28
+ ```sh
29
+ pip install some-package
30
+ ```
31
+
32
+ The implementation may obtain a pure wheel, install an already-built
33
+ SandboxedJS wheel, or ask an external build system to create and cache a wheel.
34
+ It must never install a host-native artifact by relabeling it, silently omit a
35
+ dependency, or claim support because compilation alone succeeded.
36
+
37
+ ## Current baseline
38
+
39
+ The working tree already contains staged, uncommitted work produced in an
40
+ earlier session:
41
+
42
+ - a generic setuptools cross environment;
43
+ - package-owned `setup.py` and `pyproject.toml` builds;
44
+ - C and Cython fixtures;
45
+ - the existing PyO3 path;
46
+ - side-module validation and runtime import tests;
47
+ - `docs/python/cross-build.md`, which records ten known assumptions.
48
+
49
+ Preserve those staged changes. Do not unstage, discard, rewrite wholesale, or
50
+ commit them unless the user explicitly requests it. First verify them and
51
+ record the result in `STATE.md`.
52
+
53
+ ## Scope boundary
54
+
55
+ This project owns:
56
+
57
+ - reproducible cross-build inputs;
58
+ - build/host/target dependency separation;
59
+ - package build-backend execution;
60
+ - ABI-valid wheel construction and metadata;
61
+ - wheel indexing, resolution, installation, and runtime verification;
62
+ - explicit recipes and patches for irreducibly package-specific behavior;
63
+ - compatibility evidence.
64
+
65
+ This project does not own, unless the user separately authorizes it:
66
+
67
+ - a hosted public build service;
68
+ - cloud accounts, deployment, billing, or package signing infrastructure;
69
+ - pretending raw sockets, subprocesses, GPU APIs, or unavailable operating
70
+ system capabilities exist;
71
+ - broad unrelated cleanup of SandboxedJS.
72
+
73
+ ## Definition of success
74
+
75
+ Success is a general pipeline demonstrated by several independent package
76
+ shapes, not one famous package. The final gate is described in `ROADMAP.md`.
77
+
@@ -0,0 +1,37 @@
1
+ # Capability roadmap
2
+
3
+ Advance only when the current task's exit gate passes. Each task must leave a
4
+ focused regression test.
5
+
6
+ | Order | Task | Capability produced |
7
+ | --- | --- | --- |
8
+ | 00 | `tasks/00-verify-inherited-work.md` | trusted baseline for the staged generic builder |
9
+ | 01 | `tasks/01-authoritative-metadata.md` | wheel metadata derived from the package |
10
+ | 02 | `tasks/02-native-dependencies.md` | declared target libraries and profile sysroot |
11
+ | 03 | `tasks/03-reproducible-inputs.md` | hashed sources, build tools, patches, provenance |
12
+ | 04 | `tasks/04-build-frontends.md` | explicit backend interface beyond setuptools/PyO3 |
13
+ | 05 | `tasks/05-registry-integration.md` | reproducible build output consumable by `pip` |
14
+ | 06 | `tasks/06-package-cohorts.md` | evidence across independent package shapes |
15
+ | 07 | `tasks/07-build-on-miss-boundary.md` | local protocol/spec for an eventual build service |
16
+
17
+ ## Platform completion gate
18
+
19
+ The platform milestone is complete when all of the following are true:
20
+
21
+ - Pure wheels continue to install directly and transactionally.
22
+ - Three native language/build shapes work without package-name branches.
23
+ - At least one extension links a separately built native target library.
24
+ - At least one package needs and cleanly carries a visible target patch.
25
+ - Wheel metadata and dependency resolution come from authoritative package
26
+ metadata plus explicit target constraints.
27
+ - Every indexed artifact is source-pinned, hash-verifiable, ABI-identified,
28
+ installable, importable, and behavior-tested in the owned runtime.
29
+ - A compatibility report distinguishes supported, recipe-required,
30
+ platform-blocked, and not-yet-attempted packages.
31
+ - The external build-on-miss interface is specified without embedding a
32
+ compiler toolchain in the browser runtime.
33
+
34
+ NumPy may be attempted after tasks 00-05. It is evidence for native dependency,
35
+ build-probe, memory, and scientific-stack behavior; it is not itself the
36
+ definition of platform completion.
37
+
@@ -0,0 +1,93 @@
1
+ # Execution state
2
+
3
+ Keep under roughly 120 lines. Replace stale detail instead of appending.
4
+
5
+ ## Status
6
+
7
+ - Phase: `complete`
8
+ - Blocker: none
9
+ - User decision required: none outstanding
10
+
11
+ ## Repository layout (restructured)
12
+
13
+ src/
14
+ kernel/ fs/ net/ shell/ the linux-mimicking core
15
+ node/ module shims, commonjs engine, esm transform
16
+ python/ cpython, syscalls, pip, resolver, worker, abi, local-builder
17
+ worker/ pods, sync channel, worker host
18
+ tools/ esbuild, rolldown, ffmpeg hosts
19
+ container/ pkg/ agent/ preview/ hosting/
20
+ docs/ every markdown file: agent/, python/, handoff.md
21
+ python-runtime/ the Python build pipeline (Makefile, scripts, recipes)
22
+
23
+ `src/runtime/` is gone. Moves were done with `git mv` and every relative import
24
+ recomputed programmatically. Four references were strings rather than import
25
+ specifiers -- two `dist/` paths whose depth changed, a `/src/runtime/python/`
26
+ check in config.ts, and a test allowlist -- and those caused 79 failures until
27
+ found. There was no dead code to remove: 2 of 130 source files are unreferenced
28
+ and both are ambient `.d.ts` files tsconfig loads implicitly.
29
+
30
+ ## Packages: nothing to pre-build any more
31
+
32
+ `pip install <anything>` now builds a wheel when the index has none.
33
+
34
+ - `scripts/auto_recipe.py` writes a recipe from what PyPI and the source
35
+ already state: identity, verified sdist, and the declared PEP 517 backend.
36
+ Backends with no adapter are refused by name. Build requirements the lock has
37
+ never seen are pinned at that moment rather than dropped.
38
+ - `src/python/local-builder.ts` runs the pipeline; `bin/sandboxedjs-build-wheels.mjs`
39
+ serves the index and builds on request, for browsers that have no compiler.
40
+ - Opt-in, defaulting on only in Node from a checkout. Submit-and-poll, because
41
+ a connection held open for a minutes-long build reads as an unreachable
42
+ service.
43
+ - Verified: `pip install ujson` with no recipe -> generated, built, indexed,
44
+ installed, imported, both locally and through the service.
45
+
46
+ ## Two real defects found and fixed
47
+
48
+ - The browser's default wheel index was filtered to the wheels whose bytes are
49
+ inlined in the bundle, so every other built wheel was invisible -- `pip
50
+ install numpy` reported no usable distribution while numpy sat unreferenced
51
+ beside the interpreter. The index now lists all built wheels, served from
52
+ next to the interpreter, with the inlined bytes as an overlay keyed by
53
+ filename.
54
+ - The post-build index read went through pip's memoizing cache and returned the
55
+ pre-build copy, so a package was built twice.
56
+
57
+ ## Pre-existing failures, verified not caused by this work
58
+
59
+ 11 tests, reproduced identically in a clean worktree at HEAD: `python-syscalls`
60
+ (5), `cpython` (2), `python-abi/baseline` (3), `python-runtime/asyncio` (1).
61
+ Also: pytest's default output capture fails in the container
62
+ (`OSError: [Errno 8] Bad file descriptor`), so upstream suites need
63
+ `--capture=no`.
64
+
65
+ ## Unverified
66
+
67
+ `import numpy` in a browser. The embedded browser used for testing blocks
68
+ nested module workers loaded over HTTP, which the runtime needs to start Python
69
+ at all -- `python3 --version` times out there too, and so does a trivial nested
70
+ worker. `pip install numpy` was verified in that browser and returns 0.
71
+
72
+ ## Last evidence
73
+
74
+ `npx vitest run`: 610 passed, 24 skipped, 12 failed (the 11 above plus one
75
+ PyPI-network flake that passes in isolation). `npm run typecheck`: pass.
76
+ `npm run build`: pass. All 16 wheels byte-identical across rebuilds.
77
+
78
+ ## Compact checkpoint template## Compact checkpoint template## Compact checkpoint template## Compact checkpoint template## Compact checkpoint template## Compact checkpoint template## Compact checkpoint template## Compact checkpoint template## Compact checkpoint template
79
+
80
+ Replace the sections above after each meaningful loop:
81
+
82
+ ```text
83
+ Phase: <name>
84
+ Current task: <path>
85
+ Last completed task: <path or none>
86
+ Blocker: <one sentence or none>
87
+ User decision required: <yes/no and exact decision>
88
+ Last evidence:
89
+ - <command>: <pass/fail and decisive result>
90
+ Next action: <one concrete action>
91
+ Files changed this loop: <paths>
92
+ ```
93
+
@@ -0,0 +1,36 @@
1
+ # Task 00: verify inherited generic cross-build work
2
+
3
+ ## Purpose
4
+
5
+ Establish that the staged setuptools/Cython work is real and reproducible
6
+ before building new layers on it. Do not expand scope in this task.
7
+
8
+ ## Procedure
9
+
10
+ 1. Inspect `git status --short`, `git diff --cached --check`, and the staged
11
+ diff limited to the files listed in `STATE.md`.
12
+ 2. Confirm recipes cannot provide ABI compiler or linker flags.
13
+ 3. Confirm generated artifacts are checked for WebAssembly, `dylink`, and the
14
+ derived `PyInit_*` symbol.
15
+ 4. Run the setuptools and Cython fixture builds. Rebuild the wheel index after
16
+ any wheel output changes.
17
+ 5. Run `npm run build` only if runtime bundles required by the acceptance test
18
+ are absent or older than relevant inputs.
19
+ 6. Run `npx vitest run test/python-runtime/extensions.test.ts`.
20
+ 7. Run `npm run typecheck`.
21
+
22
+ ## Exit gate
23
+
24
+ - Staged diff check passes.
25
+ - Setuptools C, Cython, and PyO3 wheels install and execute native behavior in
26
+ the owned runtime.
27
+ - Pydantic acceptance remains green.
28
+ - No test passed by weakening or skipping an ABI assertion.
29
+ - `STATE.md` contains exact passing commands and points to task 01.
30
+
31
+ ## If it fails
32
+
33
+ Use `DECISION-TREE.md`. Fix only regressions within the inherited work. After
34
+ three failed evidence-driven attempts on the same class, prepare an escalation
35
+ packet instead of redesigning the ABI.
36
+