Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/development/ENGINEERING_PLATFORM_ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,27 @@ partial-deletion SIGKILL recovery and all 15 EP lifecycle crash cells. This
EP-owned subset is `PROCESS_CRASH_QUALIFIED`; the note creates no new node,
does not change broader OI-2 status or claim installer/reboot acceptance.

## EP Server native macOS non-root runtime — 2026-09-29

The released 2.3.105 wheel has [bounded native foreground evidence](../engineering/EP_SERVER_MACOS_NONROOT_2_3_105.md)
under a separate UID 20000 on macOS arm64/Python 3.14.7. Its real Server/API
readback bound the expected instance and published wheel digest; authenticated
disposable consumer scope, wrong-identity rejection, filesystem denial,
same-UID A/B separation, a synthetic cross-UID denial, missing-provider
UNAVAILABLE state and normal restart passed. This narrows the missing
runtime/readiness portion of OI-2 and OI-5 without changing their parent
statuses. System service registration, reboot and live provider login remain
outside this native qualification. The EP-owned preserve/restore continuation
passed an adapted native preserve/restore rerun under UID 20000 with a real
initial foreground Server and a filesystem-only service adapter. Preserve
retained identity/data; restore stayed inactive and required provider
reverification. The released provisioner had inherited an inaccessible caller
working directory during the first attempt; a source correction binds its venv
and pip children to the account-owned slot. The published 2.3.105 wheel remains
unchanged. Neither rerun claims launchd, reboot or live provider authentication.
No machine-readable DAG in this repository contains OI-2 or OI-5 IDs; no new
DAG node or parallel backlog is created.

## Release and operational installation lifecycle V1 — active coordinated plan

Repository evidence recorded on 2026-09-09 reads `origin/main` as
Expand Down
5 changes: 5 additions & 0 deletions docs/engineering/EP_SERVER_DEPLOYMENT_AND_DISCOVERY.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ invokes the EP-owned provisioner. It does not construct a plist, runtime,
provider context, migration or cleanup plan. A real fresh-Mac cold boot and
provider-login fan-out remain joint installer acceptance; source qualification
does not claim that live-host result.

The [2.3.105 native macOS non-root evidence](EP_SERVER_MACOS_NONROOT_2_3_105.md)
qualifies a supervised foreground Server and its real API under a separate
test UID. It does not imply this deployment target's LaunchDaemon, cold boot,
provider login or joint installer acceptance.
100 changes: 100 additions & 0 deletions docs/engineering/EP_SERVER_MACOS_NONROOT_2_3_105.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# EP Server 2.3.105 macOS non-root qualification

This is the bounded EP-owned evidence for LANE_2 registration revision 27,
assignment `L2-EP-NONROOT-RUNTIME-CONFORMANCE-V1-20260929`. The authoritative
operator record is [Forge #142](https://github.com/pcvantol/forge/issues/142).
The existing OI-2 lifecycle and OI-5 service/readiness nodes remain the owning
roadmap subset. None of the repository's machine-readable DAG files defines
those node IDs, so this qualification adds no parallel DAG or invented node.

## Exact released artifact

| Field | Readback |
| --- | --- |
| Release | `engineering-platform-v2.3.105`, `RELEASE_COMPLETE` |
| Release source | `ad44263f6ec87ea018cda11f053fa12521ae9d79` |
| Published wheel SHA-256 | `22dd1e49c263b55dc9eee396810a09fc43509984fe685f3c00d26289d55e8adc` |
| Release receipt SHA-256 | `0b3ebeaef44c1af7808e4bdccf88bedf555e3a94e4ba5b30e1f26fab04eda1fb` |
| Interpreter | macOS arm64, Python 3.14.7; wheel requires `>=3.14,<3.15` |
| Actual Server store schema | 72 from the released source, installed module and live API |

The registration's `EP_STORAGE_SCHEMA=68` does not match the released Server
store schema 72. The wheel and release receipt digests match exactly; the
schema discrepancy is retained as a registration correction, not applied to
the published bytes or live response.

## Native foreground matrix

The locally admitted disposable account had EUID/EGID 20000, no administrator
or remote-login group, SecureToken disabled and no APFS/FileVault cryptographic
membership. A real process under that UID loaded `engineering_platform`
from a noneditable venv outside the checkout. The process inventory showed
the macOS Python 3.14.7 app executable, and the real loopback HTTP response
reported its own instance ID, version 2.3.105 and observed exact wheel digest.
The test used a scrubbed environment with explicit HOME and PATH; macOS's
`__CF_USER_TEXT_ENCODING` injection was the only allowed extra variable.

| Case | Result and boundary |
| --- | --- |
| Product initialization and A/B | Distinct disposable identities and simultaneous real HTTP servers; logical instance separation under the same UID |
| Expected identity and release | Real HTTP 200, same expected instance, version and observed wheel digest |
| Wrong expected instance | `EP_SERVER_INSTANCE_ID_MISMATCH` and nonzero exit |
| Scoped API | A product-created disposable consumer received authenticated v1.1 identity/readback; absent bearer returned 401 and wrong project scope 403. The token stayed local and was never printed in evidence |
| Filesystem | Test UID could not write the installed package; a non-writable own data parent was rejected without global permission repair |
| Cross-UID | A synthetic 0600 file owned by another already available UID was unreadable by the test UID; this is not a second EP instance |
| Provider absence | Codex and GitHub reported `UNAVAILABLE`, with no overall provider READY |
| Normal restart | Same instance, release and scoped API identity after exact-child stop/start; provider status remained `UNAVAILABLE` |
| Cleanup | Exact child stopped; independent process and listener readback found no own server |

These are real Server/process/API observations. They do not establish a
LaunchDaemon, physical reboot, live provider login, service-account installer,
production instance or full installer acceptance. The user environment was
not borrowed. No production credential, Keychain or other lane resource was
read or changed.

## Reproduction

`tools/qualification/ep_nonroot_macos_r27.py` takes explicit absolute paths
for the account's private test home, downloaded wheel, installed noneditable
venv and a synthetic 0600 other-UID fixture. Run it with that venv's Python
`-I` after an operator-approved, local role drop and `env -i` with only
`HOME`, `PATH`, `LANG`, `LC_ALL`, `TMPDIR` and
`PYTHONDONTWRITEBYTECODE`. Pass `--account`, `--expected-uid`, `--home`,
`--wheel`, `--venv` and `--synthetic-sibling-fixture`. The harness itself
must never run as root, use a checkout import as EP authority or bypass
`Requires-Python`. It creates only disposable data in the specified home and
supervises its exact Server children.

`tools/qualification/ep_nonroot_lifecycle_macos_r27.py` uses the same
published wheel and an instance-owned product root. It writes a service plist
only inside its disposable launch stand-in directory, never in macOS system
service directories. The provider executables deliberately fail and their
synthetic records serve only to exercise preserve/restore state transitions;
they do not qualify a provider login. The controller starts a real initial
foreground Server and the product's own live health verifier checks it.

Both repository harnesses were rerun under the admitted UID/GID 20000 with
the unchanged published wheel. The foreground/API harness returned
`PASS_WITH_DECLARED_LIMITS`, including independent live process and HTTP
readback, scoped authentication, HOME isolation and exact-child stop. The
lifecycle harness returned `PASS_ADAPTED_LIFECYCLE_WITH_REAL_INITIAL_SERVER`;
its service and provider limits remain as described below.

## Lifecycle boundary

The first native lifecycle attempt under UID 20000 stopped during the
product-owned immutable runtime-slot installation, before preserve/restore.
The actual pip traceback showed `PermissionError` at `os.getcwd()` because
the released provisioner inherited its caller's inaccessible working
directory. The pending source correction runs both venv creation and wheel
installation from the account-owned runtime slot. The exact 2.3.105 wheel is
unchanged; its lifecycle rerun used an accessible disposable working directory.

That rerun executed the released wheel under UID/GID 20000 with a real initial
foreground Server and a filesystem-only service adapter. Product preserve
reported `UNINSTALLED_DATA_PRESERVED`; the server was stopped and the original
identity and data stayed intact. Both deliberately failing synthetic provider
records were rejected after preserve. Product restore reported
`RESTORED_REQUIRES_PROVIDER_REVERIFICATION`, `ready=false`, and did not load
the service or generate fresh provider authentication. This is an adapted
lifecycle PASS, not a macOS system-service or live-provider-login PASS.
6 changes: 6 additions & 0 deletions docs/engineering/EP_SERVER_SYSTEM_MULTI_INSTANCE_V1.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,9 @@ foreign-operation/instance, provider-demotion and restore-after-purge controls
remained enforced by the reusable harness. This qualifies the EP-owned
process-crash subset with a filesystem-only service adapter. It does not
qualify a physical reboot, power loss, production service or installer.

The separate [macOS non-root 2.3.105 qualification](EP_SERVER_MACOS_NONROOT_2_3_105.md)
records a real foreground Server/API under UID 20000, scoped disposable
authentication, filesystem and provider-negative cases, and normal restart.
Its EP-owned preserve/restore continuation retains a distinct service-adapter
boundary and is not inferred from the process-crash results above.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "engineering-platform-browser-validation",
"private": true,
"version": "2.3.105",
"version": "2.3.106",
"scripts": {
"test:engineering-dashboard": "PYTHONPATH=src python3 -m engineering_platform.dashboard_browser_validation",
"test:engineering-dashboard-logic": "node --test tests/engineering/dashboard_status_store.test.mjs tests/engineering/ui_localization_contract.test.mjs tests/engineering/dashboard_translation.test.mjs",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "engineering-platform"
version = "2.3.105"
version = "2.3.106"
description = "Local-first Engineering Platform execution operations runtime"
readme = "README.md"
requires-python = ">=3.14,<3.15"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"platform": {
"id": "engineering-platform",
"name": "Engineering Platform",
"version": "2.3.105",
"version": "2.3.106",
"generation": 2,
"documentation_namespace": "engineering-platform",
"capability_registry_version": 1
Expand Down
8 changes: 4 additions & 4 deletions src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"bootstrap_contract": "2026.12",
"checkpoint_format": 1,
"dashboard_version": "2.3.105",
"dashboard_version": "2.3.106",
"handoff_protocol": 1,
"memory_format": 2,
"minimum_codex_cli": "0.146.0",
"inbox_protocol": 1,
"platform_version": "2.3.105",
"platform_version": "2.3.106",
"report_format": 2,
"runner_version": "2.3.105",
"runner_version": "2.3.106",
"status_model": 1,
"storage_schema": 45,
"watcher_version": "2.3.105"
"watcher_version": "2.3.106"
}
2 changes: 1 addition & 1 deletion src/engineering_platform/platform_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

SEMVER = re.compile(r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$")
CONTRACT = re.compile(r"^(\d{4})\.(0[1-9]|1[0-2])$")
CURRENT_PLATFORM_VERSION = "2.3.105"
CURRENT_PLATFORM_VERSION = "2.3.106"
MANIFEST_FIELDS = frozenset(
{
"platform_version",
Expand Down
2 changes: 2 additions & 0 deletions src/engineering_platform/system_instance_provisioner.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ def _install_slot(self, release: ReleaseRequest) -> system_installation_topology
result = subprocess.run(
(sys.executable, "-I", "-m", "venv", str(slot.venv)),
text=True, capture_output=True, check=False,
cwd=slot.root,
env={"PYTHONNOUSERSITE": "1", "PYTHONSAFEPATH": "1"},
)
if result.returncode:
Expand All @@ -717,6 +718,7 @@ def _install_slot(self, release: ReleaseRequest) -> system_installation_topology
str(release.artifact),
),
text=True, capture_output=True, check=False,
cwd=slot.root,
env={"PYTHONNOUSERSITE": "1", "PYTHONSAFEPATH": "1", "PIP_CONFIG_FILE": os.devnull},
)
if result.returncode:
Expand Down
2 changes: 1 addition & 1 deletion src/engineering_platform/templates/workspace-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"platform": {
"id": "engineering-platform",
"name": "Engineering Platform",
"version": "2.3.105",
"version": "2.3.106",
"generation": 2,
"documentation_namespace": "engineering-platform",
"capability_registry_version": 1
Expand Down
4 changes: 3 additions & 1 deletion tests/engineering/test_system_instance_provisioner.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,11 +410,13 @@ def test_runtime_slot_and_data_initialization_boundaries(self) -> None:
)
completed = SimpleNamespace(returncode=0, stdout="", stderr="")
with (
patch.object(provisioner_module.subprocess, "run", return_value=completed),
patch.object(provisioner_module.subprocess, "run", return_value=completed) as run,
patch.object(provisioner_module.operational_installation, "package_identity", return_value={"version": self.release.version}),
):
slot = concrete._install_slot(self.release)
self.assertEqual(concrete._install_slot(self.release), slot)
self.assertEqual(run.call_count, 2)
self.assertTrue(all(call.kwargs["cwd"] == slot.root for call in run.call_args_list))

instance = self._instance("ep-production-0001", "EP production")
interpreter = self.base / "python"
Expand Down
Loading
Loading